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

---
 git/.pylintrc                                      |   6 +-
 playbooks/adhoc/zabbix_setup/clean_zabbix.yml      |  37 +-
 playbooks/adhoc/zabbix_setup/create_template.yml   |  30 +-
 playbooks/adhoc/zabbix_setup/setup_zabbix.yml      |   9 +-
 .../adhoc/zabbix_setup/vars/template_heartbeat.yml |  28 +-
 .../adhoc/zabbix_setup/vars/template_os_linux.yml  | 304 +++++-----------
 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 ---------------------
 17 files changed, 1406 insertions(+), 676 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

diff --git a/git/.pylintrc b/git/.pylintrc
index af8f1656f..fe6eef6de 100644
--- a/git/.pylintrc
+++ b/git/.pylintrc
@@ -71,7 +71,7 @@ confidence=
 # no Warning level messages displayed, use"--disable=all --enable=classes
 # --disable=W"
 # w0511 - fixme - disabled because TODOs are acceptable
-disable=E1608,W1627,E1601,E1603,E1602,E1605,E1604,E1607,E1606,W1621,W1620,W1623,W1622,W1625,W1624,W1609,W1608,W1607,W1606,W1605,W1604,W1603,W1602,W1601,W1639,W1640,I0021,W1638,I0020,W1618,W1619,W1630,W1626,W1637,W1634,W1635,W1610,W1611,W1612,W1613,W1614,W1615,W1616,W1617,W1632,W1633,W0704,W1628,W1629,W1636,W0511
+disable=E1608,W1627,E1601,E1603,E1602,E1605,E1604,E1607,E1606,W1621,W1620,W1623,W1622,W1625,W1624,W1609,W1608,W1607,W1606,W1605,W1604,W1603,W1602,W1601,W1639,W1640,I0021,W1638,I0020,W1618,W1619,W1630,W1626,W1637,W1634,W1635,W1610,W1611,W1612,W1613,W1614,W1615,W1616,W1617,W1632,W1633,W0704,W1628,W1629,W1636,W0511,R0801
 
 
 [REPORTS]
@@ -205,7 +205,7 @@ docstring-min-length=-1
 [SIMILARITIES]
 
 # Minimum lines number of a similarity.
-min-similarity-lines=4
+min-similarity-lines=0
 
 # Ignore comments when computing similarities.
 ignore-comments=yes
@@ -214,7 +214,7 @@ ignore-comments=yes
 ignore-docstrings=yes
 
 # Ignore imports when computing similarities.
-ignore-imports=no
+ignore-imports=yes
 
 
 [VARIABLES]
diff --git a/playbooks/adhoc/zabbix_setup/clean_zabbix.yml b/playbooks/adhoc/zabbix_setup/clean_zabbix.yml
index 610d18b28..a31cbef65 100644
--- a/playbooks/adhoc/zabbix_setup/clean_zabbix.yml
+++ b/playbooks/adhoc/zabbix_setup/clean_zabbix.yml
@@ -2,67 +2,50 @@
 - hosts: localhost
   gather_facts: no
   vars:
-    # Use this for local ZAIO
     g_zserver: http://localhost/zabbix/api_jsonrpc.php
-
     g_zuser: Admin
     g_zpassword: zabbix
   roles:
-  - ../roles/os_zabbix
+  - ../../../roles/os_zabbix
   post_tasks:
 
-  - zbxapi:
+  - zbx_template:
       server: "{{ g_zserver }}"
       user: "{{ g_zuser }}"
       password: "{{ g_zpassword }}"
-      zbx_class: Template
       state: list
-      params:
-        output: extend
-        search:
-          host: 'Template Heartbeat'
+      name: 'Template Heartbeat'
     register: templ_heartbeat
 
-  - zbxapi:
+  - zbx_template:
       server: "{{ g_zserver }}"
       user: "{{ g_zuser }}"
       password: "{{ g_zpassword }}"
-      zbx_class: Template
       state: list
-      params:
-        output: extend
-        search:
-          host: 'Template App Zabbix Server'
+      name: 'Template App Zabbix Server'
     register: templ_zabbix_server
 
-  - zbxapi:
+  - zbx_template:
       server: "{{ g_zserver }}"
       user: "{{ g_zuser }}"
       password: "{{ g_zpassword }}"
-      zbx_class: Template
       state: list
-      params:
-        output: extend
-        search:
-          host: 'Template App Zabbix Agent'
+      name: 'Template App Zabbix Agent'
     register: templ_zabbix_agent
 
-  - zbxapi:
+  - zbx_template:
       server: "{{ g_zserver }}"
       user: "{{ g_zuser }}"
       password: "{{ g_zpassword }}"
-      zbx_class: Template
       state: list
     register: templates
 
   - debug: var=templ_heartbeat.results
 
-  - zbxapi:
+  - zbx_template:
       server: "{{ g_zserver }}"
       user: "{{ g_zuser }}"
       password: "{{ g_zpassword }}"
-      zbx_class: Template
       state: absent
-      params: "{{templates.results | difference(templ_zabbix_agent.results) | difference(templ_zabbix_server.results) | oo_collect('templateid') }}"
-    register: template_results
+    with_items: "{{ templates.results | difference(templ_zabbix_agent.results) | difference(templ_zabbix_server.results) | oo_collect('host') }}"
     when:  templ_heartbeat.results | length == 0
diff --git a/playbooks/adhoc/zabbix_setup/create_template.yml b/playbooks/adhoc/zabbix_setup/create_template.yml
index b055e78eb..60fb27666 100644
--- a/playbooks/adhoc/zabbix_setup/create_template.yml
+++ b/playbooks/adhoc/zabbix_setup/create_template.yml
@@ -2,16 +2,14 @@
 - debug: var=ctp_template
 
 - name: Create Template
-  zbxapi:
+  zbx_template:
     server: "{{ ctp_zserver }}"
     user: "{{ ctp_zuser }}"
     password: "{{ ctp_zpassword }}"
-    zbx_class: Template
-    state: present
-    params: "{{ ctp_template.params }}"
-  register: ctp_created_templates
+    name: "{{ ctp_template.name }}"
+  register: ctp_created_template
 
-- debug: var=ctp_created_templates
+- debug: var=ctp_created_template
 
 #- name: Create Application
 #  zbxapi:
@@ -22,7 +20,7 @@
 #    state: present
 #    params:
 #      name: "{{ ctp_template.application.name}}"
-#      hostid: "{{ ctp_created_templates.results[0].templateid }}"
+#      hostid: "{{ ctp_created_template.results[0].templateid }}"
 #      search:
 #        name: "{{ ctp_template.application.name}}"
 #  register: ctp_created_application
@@ -30,28 +28,28 @@
 #- debug: var=ctp_created_application
 
 - name: Create Items
-  zbxapi:
+  zbx_item:
     server: "{{ ctp_zserver }}"
     user: "{{ ctp_zuser }}"
     password: "{{ ctp_zpassword }}"
-    zbx_class: Item
-    state: present
-    params: "{{ item | oo_set_zbx_item_hostid(ctp_created_templates.results) }}"
+    name: "{{ item.name }}"
+    key: "{{ item.key }}"
+    value_type: "{{ item.value_type | default('int') }}"
+    template_name: "{{ ctp_template.name }}"
   with_items: ctp_template.zitems
   register: ctp_created_items
 
 #- debug: var=ctp_created_items
 
 - name: Create Triggers
-  zbxapi:
+  zbx_trigger:
     server: "{{ ctp_zserver }}"
     user: "{{ ctp_zuser }}"
     password: "{{ ctp_zpassword }}"
-    zbx_class: Trigger
-    state: present
-    params: "{{ item }}"
+    description: "{{ item.description }}"
+    expression: "{{ item.expression }}"
+    priority: "{{ item.priority }}"
   with_items: ctp_template.ztriggers
-  register: ctp_created_triggers
   when: ctp_template.ztriggers is defined
 
 #- debug: var=ctp_created_triggers
diff --git a/playbooks/adhoc/zabbix_setup/setup_zabbix.yml b/playbooks/adhoc/zabbix_setup/setup_zabbix.yml
index 8b44f2adf..1729194b5 100644
--- a/playbooks/adhoc/zabbix_setup/setup_zabbix.yml
+++ b/playbooks/adhoc/zabbix_setup/setup_zabbix.yml
@@ -5,22 +5,17 @@
   - vars/template_heartbeat.yml
   - vars/template_os_linux.yml
   vars:
-    # Use this for local ZAIO
     g_zserver: http://localhost/zabbix/api_jsonrpc.php
-
     g_zuser: Admin
     g_zpassword: zabbix
   roles:
-  - ../roles/os_zabbix
+  - ../../../roles/os_zabbix
   post_tasks:
-  - zbxapi:
+  - zbx_template:
       server: "{{ g_zserver }}"
       user: "{{ g_zuser }}"
       password: "{{ g_zpassword }}"
-      zbx_class: Template
       state: list
-      params:
-        output: extend
     register: templates
 
   - debug: var=templates
diff --git a/playbooks/adhoc/zabbix_setup/vars/template_heartbeat.yml b/playbooks/adhoc/zabbix_setup/vars/template_heartbeat.yml
index 9d6145ec4..22cc75554 100644
--- a/playbooks/adhoc/zabbix_setup/vars/template_heartbeat.yml
+++ b/playbooks/adhoc/zabbix_setup/vars/template_heartbeat.yml
@@ -1,33 +1,11 @@
 ---
 g_template_heartbeat:
-  application:
-    name: Heartbeat
-#output: extend
-    search:
-      name: Heartbeat
-  params:
-    name: Template Heartbeat
-    host: Template Heartbeat
-    groups:
-    - groupid: 1 # FIXME (not real)
-    output: extend
-    search:
-      name: Template Heartbeat
+  name: Template Heartbeat
   zitems:
   - name: Heartbeat Ping
     hostid:
-    key_: heartbeat.ping
-    type: 2
-    value_type: 1
-    output: extend
-    search:
-      key_: heartbeat.ping
-    selectApplications: extend
+    key: heartbeat.ping
   ztriggers:
   - description: 'Heartbeat.ping has failed on {HOST.NAME}'
     expression: '{Template Heartbeat:heartbeat.ping.last()}<>0'
-    priority: 3
-    searchWildcardsEnabled: True
-    search:
-      description: 'Heartbeat.ping has failed on*'
-    expandExpression: True
+    priority: avg
diff --git a/playbooks/adhoc/zabbix_setup/vars/template_os_linux.yml b/playbooks/adhoc/zabbix_setup/vars/template_os_linux.yml
index b89711632..6fab08879 100644
--- a/playbooks/adhoc/zabbix_setup/vars/template_os_linux.yml
+++ b/playbooks/adhoc/zabbix_setup/vars/template_os_linux.yml
@@ -1,248 +1,120 @@
 ---
 g_template_os_linux:
-  application:
-    name: OS Linux
-    output: extend
-    search:
-      name: OS Linux
-  params:
-    name: Template OS Linux
-    host: Template OS Linux
-    groups:
-    - groupid: 1 # FIXME (not real)
-    output: extend
-    search:
-      name: Template OS Linux
+  name: Template OS Linux
   zitems:
-  - hostid: null
-    key_: kernel.uname.sysname
+  - key: kernel.uname.sysname
     name: kernel.uname.sysname
-    search:
-      key_: kernel.uname.sysname
-    type: 2
-    value_type: 4
-    selectApplications: extend
-  - hostid: null
-    key_: kernel.all.cpu.wait.total
+    value_type: string
+
+  - key: kernel.all.cpu.wait.total
     name: kernel.all.cpu.wait.total
-    search:
-      key_: kernel.all.cpu.wait.total
-    type: 2
-    value_type: 3
-    selectApplications: extend
-  - hostid: null
-    key_: kernel.all.cpu.irq.hard
+    value_type: int
+
+  - key: kernel.all.cpu.irq.hard
     name: kernel.all.cpu.irq.hard
-    search:
-      key_: kernel.all.cpu.irq.hard
-    type: 2
-    value_type: 3
-    selectApplications: extend
-  - hostid: null
-    key_: kernel.all.cpu.idle
+    value_type: int
+
+  - key: kernel.all.cpu.idle
     name: kernel.all.cpu.idle
-    search:
-      key_: kernel.all.cpu.idle
-    type: 2
-    value_type: 3
-    selectApplications: extend
-  - hostid: null
-    key_: kernel.uname.distro
+    value_type: int
+
+  - key: kernel.uname.distro
     name: kernel.uname.distro
-    search:
-      key_: kernel.uname.distro
-    type: 2
-    value_type: 4
-    selectApplications: extend
-  - hostid: null
-    key_: kernel.uname.nodename
+    value_type: string
+
+  - key: kernel.uname.nodename
     name: kernel.uname.nodename
-    search:
-      key_: kernel.uname.nodename
-    type: 2
-    value_type: 4
-    selectApplications: extend
-  - hostid: null
-    key_: kernel.all.cpu.irq.soft
+    value_type: string
+
+  - key: kernel.all.cpu.irq.soft
     name: kernel.all.cpu.irq.soft
-    search:
-      key_: kernel.all.cpu.irq.soft
-    type: 2
-    value_type: 3
-    selectApplications: extend
-  - hostid: null
-    key_: kernel.all.load.15_minute
+    value_type: int
+
+  - key: kernel.all.load.15_minute
     name: kernel.all.load.15_minute
-    search:
-      key_: kernel.all.load.15_minute
-    type: 2
-    value_type: 0
-    selectApplications: extend
-  - hostid: null
-    key_: kernel.all.cpu.sys
+    value_type: float
+
+  - key: kernel.all.cpu.sys
     name: kernel.all.cpu.sys
-    search:
-      key_: kernel.all.cpu.sys
-    type: 2
-    value_type: 3
-    selectApplications: extend
-  - hostid: null
-    key_: kernel.all.load.5_minute
+    value_type: int
+
+  - key: kernel.all.load.5_minute
     name: kernel.all.load.5_minute
-    search:
-      key_: kernel.all.load.5_minute
-    type: 2
-    value_type: 0
-    selectApplications: extend
-  - hostid: null
-    key_: mem.freemem
+    value_type: float
+
+  - key: mem.freemem
     name: mem.freemem
-    search:
-      key_: mem.freemem
-    type: 2
-    value_type: 3
-    selectApplications: extend
-  - hostid: null
-    key_: kernel.all.cpu.nice
+    value_type: int
+
+  - key: kernel.all.cpu.nice
     name: kernel.all.cpu.nice
-    search:
-      key_: kernel.all.cpu.nice
-    type: 2
-    value_type: 3
-    selectApplications: extend
-  - hostid: null
-    key_: mem.util.bufmem
+    value_type: int
+
+  - key: mem.util.bufmem
     name: mem.util.bufmem
-    search:
-      key_: mem.util.bufmem
-    type: 2
-    value_type: 3
-    selectApplications: extend
-  - hostid: null
-    key_: swap.used
+    value_type: int
+
+  - key: swap.used
     name: swap.used
-    search:
-      key_: swap.used
-    type: 2
-    value_type: 3
-    selectApplications: extend
-  - hostid: null
-    key_: kernel.all.load.1_minute
+    value_type: int
+
+  - key: kernel.all.load.1_minute
     name: kernel.all.load.1_minute
-    search:
-      key_: kernel.all.load.1_minute
-    type: 2
-    value_type: 0
-    selectApplications: extend
-  - hostid: null
-    key_: kernel.uname.version
+    value_type: float
+
+  - key: kernel.uname.version
     name: kernel.uname.version
-    search:
-      key_: kernel.uname.version
-    type: 2
-    value_type: 4
-    selectApplications: extend
-  - hostid: null
-    key_: swap.length
+    value_type: string
+
+  - key: swap.length
     name: swap.length
-    search:
-      key_: swap.length
-    type: 2
-    value_type: 3
-    selectApplications: extend
-  - hostid: null
-    key_: mem.physmem
+    value_type: int
+
+  - key: mem.physmem
     name: mem.physmem
-    search:
-      key_: mem.physmem
-    type: 2
-    value_type: 3
-    selectApplications: extend
-  - hostid: null
-    key_: kernel.all.uptime
+    value_type: int
+
+  - key: kernel.all.uptime
     name: kernel.all.uptime
-    search:
-      key_: kernel.all.uptime
-    type: 2
-    value_type: 3
-    selectApplications: extend
-  - hostid: null
-    key_: swap.free
+    value_type: int
+
+  - key: swap.free
     name: swap.free
-    search:
-      key_: swap.free
-    type: 2
-    value_type: 3
-    selectApplications: extend
-  - hostid: null
-    key_: mem.util.used
+    value_type: int
+
+  - key: mem.util.used
     name: mem.util.used
-    search:
-      key_: mem.util.used
-    type: 2
-    value_type: 3
-    selectApplications: extend
-  - hostid: null
-    key_: kernel.all.cpu.user
+    value_type: int
+
+  - key: kernel.all.cpu.user
     name: kernel.all.cpu.user
-    search:
-      key_: kernel.all.cpu.user
-    type: 2
-    value_type: 3
-    selectApplications: extend
-  - hostid: null
-    key_: kernel.uname.machine
+    value_type: int
+
+  - key: kernel.uname.machine
     name: kernel.uname.machine
-    search:
-      key_: kernel.uname.machine
-    type: 2
-    value_type: 4
-    selectApplications: extend
-  - hostid: null
-    key_: hinv.ncpu
+    value_type: string
+
+  - key: hinv.ncpu
     name: hinv.ncpu
-    search:
-      key_: hinv.ncpu
-    type: 2
-    value_type: 3
-    selectApplications: extend
-  - hostid: null
-    key_: mem.util.cached
+    value_type: int
+
+  - key: mem.util.cached
     name: mem.util.cached
-    search:
-      key_: mem.util.cached
-    type: 2
-    value_type: 3
-    selectApplications: extend
-  - hostid: null
-    key_: kernel.all.cpu.steal
+    value_type: int
+
+  - key: kernel.all.cpu.steal
     name: kernel.all.cpu.steal
-    search:
-      key_: kernel.all.cpu.steal
-    type: 2
-    value_type: 3
-    selectApplications: extend
-  - hostid: null
-    key_: kernel.all.pswitch
+    value_type: int
+
+
+  - key: kernel.all.pswitch
     name: kernel.all.pswitch
-    search:
-      key_: kernel.all.pswitch
-    type: 2
-    value_type: 3
-    selectApplications: extend
-  - hostid: null
-    key_: kernel.uname.release
+    value_type: int
+
+  - key: kernel.uname.release
     name: kernel.uname.release
-    search:
-      key_: kernel.uname.release
-    type: 2
-    value_type: 4
-    selectApplications: extend
-  - hostid: null
-    key_: proc.nprocs
+    value_type: string
+
+  - key: proc.nprocs
     name: proc.nprocs
-    search:
-      key_: proc.nprocs
-    type: 2
-    value_type: 3
-    selectApplications: extend
+    value_type: int
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