summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README_AWS.md22
-rw-r--r--README_OSE.md17
-rw-r--r--README_libvirt.md7
-rw-r--r--README_origin.md18
-rw-r--r--playbooks/adhoc/grow_docker_vg/filter_plugins/oo_filters.py41
-rw-r--r--playbooks/adhoc/grow_docker_vg/grow_docker_vg.yml206
-rw-r--r--playbooks/adhoc/s3_registry/s3_registry.j220
-rw-r--r--playbooks/adhoc/s3_registry/s3_registry.yml50
-rw-r--r--roles/ansible_tower/tasks/main.yaml3
-rw-r--r--roles/lib_zabbix/library/zbx_action.py538
-rw-r--r--roles/lib_zabbix/library/zbx_discoveryrule.py36
-rw-r--r--roles/lib_zabbix/library/zbx_itemprototype.py61
-rw-r--r--roles/lib_zabbix/library/zbx_trigger.py18
-rw-r--r--roles/lib_zabbix/library/zbx_triggerprototype.py177
-rw-r--r--roles/lib_zabbix/library/zbx_user_media.py53
-rw-r--r--roles/lib_zabbix/tasks/create_template.yml41
-rwxr-xr-xroles/openshift_facts/library/openshift_facts.py2
-rw-r--r--roles/os_zabbix/vars/template_os_linux.yml29
18 files changed, 1263 insertions, 76 deletions
diff --git a/README_AWS.md b/README_AWS.md
index c511741b9..3a5790eb3 100644
--- a/README_AWS.md
+++ b/README_AWS.md
@@ -154,18 +154,10 @@ Note: If no deployment type is specified, then the default is origin.
## Post-ansible steps
-Create the default router
--------------------------
-On the master host:
-```sh
-oadm router --create=true \
- --credentials=/etc/openshift/master/openshift-router.kubeconfig
-```
-
-Create the default docker-registry
-----------------------------------
-On the master host:
-```sh
-oadm registry --create=true \
- --credentials=/etc/openshift/master/openshift-registry.kubeconfig
-``` \ No newline at end of file
+
+You should now be ready to follow the **What's Next?** section of the advanced installation guide to deploy your router, registry, and other components.
+
+Refer to the advanced installation guide for your deployment type:
+
+* [OpenShift Enterprise](https://docs.openshift.com/enterprise/3.0/install_config/install/advanced_install.html#what-s-next)
+* [OpenShift Origin](https://docs.openshift.org/latest/install_config/install/advanced_install.html#what-s-next)
diff --git a/README_OSE.md b/README_OSE.md
index cce1ec030..79ad07044 100644
--- a/README_OSE.md
+++ b/README_OSE.md
@@ -101,6 +101,7 @@ ose3-master.example.com
# host group for nodes
[nodes]
+ose3-master.example.com
ose3-node[1:2].example.com
```
@@ -116,22 +117,8 @@ ansible-playbook playbooks/byo/config.yml
inventory file use the -i option for ansible-playbook.
## Post-ansible steps
-#### Create the default router
-On the master host:
-```sh
-oadm router --create=true \
- --credentials=/etc/openshift/master/openshift-router.kubeconfig \
- --images='rcm-img-docker01.build.eng.bos.redhat.com:5001/openshift3/ose-${component}:${version}'
-```
-#### Create the default docker-registry
-On the master host:
-```sh
-oadm registry --create=true \
- --credentials=/etc/openshift/master/openshift-registry.kubeconfig \
- --images='rcm-img-docker01.build.eng.bos.redhat.com:5001/openshift3/ose-${component}:${version}' \
- --mount-host=/var/lib/openshift/docker-registry
-```
+You should now be ready to follow the [What's Next?](https://docs.openshift.com/enterprise/3.0/install_config/install/advanced_install.html#what-s-next) section of the advanced installation guide to deploy your router, registry, and other components.
## Overriding detected ip addresses and hostnames
Some deployments will require that the user override the detected hostnames
diff --git a/README_libvirt.md b/README_libvirt.md
index 60af0ac88..1a710ff3b 100644
--- a/README_libvirt.md
+++ b/README_libvirt.md
@@ -68,7 +68,12 @@ If your `$HOME` is world readable, everything is fine. If your `$HOME` is privat
error: Cannot access storage file '$HOME/libvirt-storage-pool-openshift/lenaic-master-216d8.qcow2' (as uid:99, gid:78): Permission denied
```
-In order to fix that issue, you have several possibilities:* set `libvirt_storage_pool_path` inside `playbooks/libvirt/openshift-cluster/launch.yml` and `playbooks/libvirt/openshift-cluster/terminate.yml` to a directory: * backed by a filesystem with a lot of free disk space * writable by your user; * accessible by the qemu user.* Grant the qemu user access to the storage pool.
+In order to fix that issue, you have several possibilities:
+ * set `libvirt_storage_pool_path` inside `playbooks/libvirt/openshift-cluster/launch.yml` and `playbooks/libvirt/openshift-cluster/terminate.yml` to a directory:
+ * backed by a filesystem with a lot of free disk space
+ * writable by your user;
+ * accessible by the qemu user.
+ * Grant the qemu user access to the storage pool.
On Arch:
diff --git a/README_origin.md b/README_origin.md
index f13fe660a..cb213a93a 100644
--- a/README_origin.md
+++ b/README_origin.md
@@ -73,6 +73,7 @@ osv3-master.example.com
# host group for nodes
[nodes]
+osv3-master.example.com
osv3-node[1:2].example.com
```
@@ -88,23 +89,8 @@ ansible-playbook playbooks/byo/config.yml
inventory file use the -i option for ansible-playbook.
## Post-ansible steps
-#### Create the default router
-On the master host:
-```sh
-oadm router --create=true \
- --credentials=/etc/openshift/master/openshift-router.kubeconfig
-```
-
-#### Create the default docker-registry
-On the master host:
-```sh
-oadm registry --create=true \
- --credentials=/etc/openshift/master/openshift-registry.kubeconfig
-```
-If you would like persistent storage, refer to the
-[OpenShift documentation](https://docs.openshift.org/latest/admin_guide/install/docker_registry.html)
-for more information on deployment options for the built in docker-registry.
+You should now be ready to follow the [What's Next?](https://docs.openshift.org/latest/install_config/install/advanced_install.html#what-s-next) section of the advanced installation guide to deploy your router, registry, and other components.
## Overriding detected ip addresses and hostnames
Some deployments will require that the user override the detected hostnames
diff --git a/playbooks/adhoc/grow_docker_vg/filter_plugins/oo_filters.py b/playbooks/adhoc/grow_docker_vg/filter_plugins/oo_filters.py
new file mode 100644
index 000000000..d0264cde9
--- /dev/null
+++ b/playbooks/adhoc/grow_docker_vg/filter_plugins/oo_filters.py
@@ -0,0 +1,41 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# vim: expandtab:tabstop=4:shiftwidth=4
+'''
+Custom filters for use in openshift-ansible
+'''
+
+import pdb
+
+
+class FilterModule(object):
+ ''' Custom ansible filters '''
+
+ @staticmethod
+ def oo_pdb(arg):
+ ''' This pops you into a pdb instance where arg is the data passed in
+ from the filter.
+ Ex: "{{ hostvars | oo_pdb }}"
+ '''
+ pdb.set_trace()
+ return arg
+
+ @staticmethod
+ def translate_volume_name(volumes, target_volume):
+ '''
+ This filter matches a device string /dev/sdX to /dev/xvdX
+ It will then return the AWS volume ID
+ '''
+ for vol in volumes:
+ translated_name = vol["attachment_set"]["device"].replace("/dev/sd", "/dev/xvd")
+ if target_volume.startswith(translated_name):
+ return vol["id"]
+
+ return None
+
+
+ def filters(self):
+ ''' returns a mapping of filters to methods '''
+ return {
+ "translate_volume_name": self.translate_volume_name,
+ }
diff --git a/playbooks/adhoc/grow_docker_vg/grow_docker_vg.yml b/playbooks/adhoc/grow_docker_vg/grow_docker_vg.yml
new file mode 100644
index 000000000..ef9b45abd
--- /dev/null
+++ b/playbooks/adhoc/grow_docker_vg/grow_docker_vg.yml
@@ -0,0 +1,206 @@
+---
+# This playbook grows the docker VG on a node by:
+# * add a new volume
+# * add volume to the existing VG.
+# * pv move to the new volume.
+# * remove old volume
+# * detach volume
+# * mark old volume in AWS with "REMOVE ME" tag
+# * grow docker LVM to 90% of the VG
+#
+# To run:
+# 1. Source your AWS credentials (make sure it's the corresponding AWS account) into your environment
+# export AWS_ACCESS_KEY_ID='XXXXX'
+# export AWS_SECRET_ACCESS_KEY='XXXXXX'
+#
+# 2. run the playbook:
+# ansible-playbook -e 'cli_tag_name=<tag-name>' grow_docker_vg.yml
+#
+# Example:
+# ansible-playbook -e 'cli_tag_name=ops-compute-12345' grow_docker_vg.yml
+#
+# Notes:
+# * By default this will do a 55GB GP2 volume. The can be overidden with the "-e 'cli_volume_size=100'" variable
+# * This does a GP2 by default. Support for Provisioned IOPS has not been added
+# * This will assign the new volume to /dev/xvdc. This is not variablized, yet.
+# * This can be done with NO downtime on the host
+# * This playbook assumes that there is a Logical Volume that is installed and called "docker-pool". This is
+# the LV that gets created via the "docker-storage-setup" command
+#
+
+- name: Grow the docker volume group
+ hosts: "tag_Name_{{ cli_tag_name }}"
+ user: root
+ connection: ssh
+ gather_facts: no
+
+ vars:
+ cli_volume_type: gp2
+ cli_volume_size: 55
+# cli_volume_iops: "{{ 30 * cli_volume_size }}"
+
+ pre_tasks:
+ - fail:
+ msg: "This playbook requires {{item}} to be set."
+ when: "{{ item }} is not defined or {{ item }} == ''"
+ with_items:
+ - cli_tag_name
+ - cli_volume_size
+
+ - debug:
+ var: hosts
+
+ - name: start docker
+ service:
+ name: docker
+ state: started
+
+ - name: Determine if Storage Driver (docker info) is devicemapper
+ shell: docker info | grep 'Storage Driver:.*devicemapper'
+ register: device_mapper_check
+ ignore_errors: yes
+
+ - debug:
+ var: device_mapper_check
+
+ - name: fail if we don't detect devicemapper
+ fail:
+ msg: The "Storage Driver" in "docker info" is not set to "devicemapper"! Please investigate manually.
+ when: device_mapper_check.rc == 1
+
+ # docker-storage-setup creates a docker-pool as the lvm. I am using docker-pool lvm to test
+ # and find the volume group.
+ - name: Attempt to find the Volume Group that docker is using
+ shell: lvs | grep docker-pool | awk '{print $2}'
+ register: docker_vg_name
+ ignore_errors: yes
+
+ - debug:
+ var: docker_vg_name
+
+ - name: fail if we don't find a docker volume group
+ fail:
+ msg: Unable to find docker volume group. Please investigate manually.
+ when: docker_vg_name.stdout_lines|length != 1
+
+ # docker-storage-setup creates a docker-pool as the lvm. I am using docker-pool lvm to test
+ # and find the physical volume.
+ - name: Attempt to find the Phyisical Volume that docker is using
+ shell: "pvs | grep {{ docker_vg_name.stdout }} | awk '{print $1}'"
+ register: docker_pv_name
+ ignore_errors: yes
+
+ - debug:
+ var: docker_pv_name
+
+ - name: fail if we don't find a docker physical volume
+ fail:
+ msg: Unable to find docker physical volume. Please investigate manually.
+ when: docker_pv_name.stdout_lines|length != 1
+
+
+ - name: get list of volumes from AWS
+ delegate_to: localhost
+ ec2_vol:
+ state: list
+ instance: "{{ ec2_id }}"
+ region: "{{ ec2_region }}"
+ register: attached_volumes
+
+ - debug: var=attached_volumes
+
+ - name: get volume id of current docker volume
+ set_fact:
+ old_docker_volume_id: "{{ attached_volumes.volumes | translate_volume_name(docker_pv_name.stdout) }}"
+
+ - debug: var=old_docker_volume_id
+
+ - name: check to see if /dev/xvdc exists
+ command: test -e /dev/xvdc
+ register: xvdc_check
+ ignore_errors: yes
+
+ - debug: var=xvdc_check
+
+ - name: fail if /dev/xvdc already exists
+ fail:
+ msg: /dev/xvdc already exists. Please investigate
+ when: xvdc_check.rc == 0
+
+ - name: Create a volume and attach it
+ delegate_to: localhost
+ ec2_vol:
+ state: present
+ instance: "{{ ec2_id }}"
+ region: "{{ ec2_region }}"
+ volume_size: "{{ cli_volume_size | default(30, True)}}"
+ volume_type: "{{ cli_volume_type }}"
+ device_name: /dev/xvdc
+ register: create_volume
+
+ - debug: var=create_volume
+
+ - name: Fail when problems creating volumes and attaching
+ fail:
+ msg: "Failed to create or attach volume msg: {{ create_volume.msg }}"
+ when: create_volume.msg is defined
+
+ - name: tag the vol with a name
+ delegate_to: localhost
+ ec2_tag: region={{ ec2_region }} resource={{ create_volume.volume_id }}
+ args:
+ tags:
+ Name: "{{ ec2_tag_Name }}"
+ env: "{{ ec2_tag_environment }}"
+ register: voltags
+
+ - name: check for attached drive
+ command: test -b /dev/xvdc
+ register: attachment_check
+ until: attachment_check.rc == 0
+ retries: 30
+ delay: 2
+
+ - name: partition the new drive and make it lvm
+ command: parted /dev/xvdc --script -- mklabel msdos mkpart primary 0% 100% set 1 lvm
+
+ - name: pvcreate /dev/xvdc
+ command: pvcreate /dev/xvdc1
+
+ - name: Extend the docker volume group
+ command: vgextend "{{ docker_vg_name.stdout }}" /dev/xvdc1
+
+ - name: pvmove onto new volume
+ command: "pvmove {{ docker_pv_name.stdout }} /dev/xvdc1"
+ async: 3600
+ poll: 10
+
+ - name: Remove the old docker drive from the volume group
+ command: "vgreduce {{ docker_vg_name.stdout }} {{ docker_pv_name.stdout }}"
+
+ - name: Remove the pv from the old drive
+ command: "pvremove {{ docker_pv_name.stdout }}"
+
+ - name: Extend the docker lvm
+ command: "lvextend -l '90%VG' /dev/{{ docker_vg_name.stdout }}/docker-pool"
+
+ - name: detach old docker volume
+ delegate_to: localhost
+ ec2_vol:
+ region: "{{ ec2_region }}"
+ id: "{{ old_docker_volume_id }}"
+ instance: None
+
+ - name: tag the old vol valid label
+ delegate_to: localhost
+ ec2_tag: region={{ ec2_region }} resource={{old_docker_volume_id}}
+ args:
+ tags:
+ Name: "{{ ec2_tag_Name }} REMOVE ME"
+ register: voltags
+
+ - name: Update the /etc/sysconfig/docker-storage-setup with new device
+ lineinfile:
+ dest: /etc/sysconfig/docker-storage-setup
+ regexp: ^DEVS=
+ line: DEVS=/dev/xvdc
diff --git a/playbooks/adhoc/s3_registry/s3_registry.j2 b/playbooks/adhoc/s3_registry/s3_registry.j2
new file mode 100644
index 000000000..026b24456
--- /dev/null
+++ b/playbooks/adhoc/s3_registry/s3_registry.j2
@@ -0,0 +1,20 @@
+version: 0.1
+log:
+ level: debug
+http:
+ addr: :5000
+storage:
+ cache:
+ layerinfo: inmemory
+ s3:
+ accesskey: {{ accesskey }}
+ secretkey: {{ secretkey }}
+ region: us-east-1
+ bucket: {{ clusterid }}-docker
+ encrypt: true
+ secure: true
+ v4auth: true
+ rootdirectory: /registry
+middleware:
+ repository:
+ - name: openshift
diff --git a/playbooks/adhoc/s3_registry/s3_registry.yml b/playbooks/adhoc/s3_registry/s3_registry.yml
new file mode 100644
index 000000000..30b873db3
--- /dev/null
+++ b/playbooks/adhoc/s3_registry/s3_registry.yml
@@ -0,0 +1,50 @@
+---
+# This playbook creates an S3 bucket named after your cluster and configures the docker-registry service to use the bucket as its backend storage.
+# Usage:
+# ansible-playbook s3_registry.yml -e accesskey="S3 aws access key" -e secretkey="S3 aws secret key" -e clusterid="mycluster"
+#
+# The AWS access/secret keys should be the keys of a separate user (not your main user), containing only the necessary S3 access role.
+# The 'clusterid' is the short name of your cluster.
+
+- hosts: security_group_{{ clusterid }}_master
+ remote_user: root
+ gather_facts: False
+
+ tasks:
+
+ - name: Create S3 bucket
+ local_action:
+ module: s3 bucket="{{ clusterid }}-docker" mode=create aws_access_key={{ accesskey|quote }} aws_secret_key={{ secretkey|quote }}
+
+ - name: Generate docker registry config
+ template: src="s3_registry.j2" dest="/root/config.yml" owner=root mode=0600
+
+ - name: Determine if new secrets are needed
+ command: oc get secrets
+ register: secrets
+
+ - name: Create registry secrets
+ command: oc secrets new dockerregistry /root/config.yml
+ when: "'dockerregistry' not in secrets.stdout"
+
+ - name: Determine if service account contains secrets
+ command: oc describe serviceaccount/registry
+ register: serviceaccount
+
+ - name: Add secrets to registry service account
+ command: oc secrets add serviceaccount/registry secrets/dockerregistry
+ when: "'dockerregistry' not in serviceaccount.stdout"
+
+ - name: Determine if deployment config contains secrets
+ command: oc volume dc/docker-registry --list
+ register: dc
+
+ - name: Add secrets to registry deployment config
+ command: oc volume dc/docker-registry --add --name=dockersecrets -m /etc/registryconfig --type=secret --secret-name=dockerregistry
+ when: "'dockersecrets' not in dc.stdout"
+
+ - name: Scale up registry
+ command: oc scale --replicas=1 dc/docker-registry
+
+ - name: Delete temporary config file
+ file: path=/root/config.yml state=absent
diff --git a/roles/ansible_tower/tasks/main.yaml b/roles/ansible_tower/tasks/main.yaml
index c110a3b70..b7757214d 100644
--- a/roles/ansible_tower/tasks/main.yaml
+++ b/roles/ansible_tower/tasks/main.yaml
@@ -9,6 +9,7 @@
- ansible
- telnet
- ack
+ - pylint
- name: download Tower setup
get_url: url=http://releases.ansible.com/ansible-tower/setup/ansible-tower-setup-2.1.1.tar.gz dest=/opt/ force=no
@@ -38,5 +39,3 @@
regexp: "^({{ item.option }})( *)="
line: '\1\2= {{ item.value }}'
with_items: config_changes | default([], true)
-
-
diff --git a/roles/lib_zabbix/library/zbx_action.py b/roles/lib_zabbix/library/zbx_action.py
new file mode 100644
index 000000000..d64cebae1
--- /dev/null
+++ b/roles/lib_zabbix/library/zbx_action.py
@@ -0,0 +1,538 @@
+#!/usr/bin/env python
+'''
+ Ansible module for zabbix actions
+'''
+# vim: expandtab:tabstop=4:shiftwidth=4
+#
+# Zabbix action ansible module
+#
+#
+# Copyright 2015 Red Hat Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This is in place because each module looks similar to each other.
+# These need duplicate code as their behavior is very similar
+# but different for each zabbix class.
+# pylint: disable=duplicate-code
+
+# pylint: disable=import-error
+from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection, ZabbixAPIError
+
+def exists(content, key='result'):
+ ''' Check if key exists in content or the size of content[key] > 0
+ '''
+ if not content.has_key(key):
+ return False
+
+ if not content[key]:
+ return False
+
+ return True
+
+def conditions_equal(zab_conditions, user_conditions):
+ '''Compare two lists of conditions'''
+ c_type = 'conditiontype'
+ _op = 'operator'
+ val = 'value'
+ if len(user_conditions) != len(zab_conditions):
+ return False
+
+ for zab_cond, user_cond in zip(zab_conditions, user_conditions):
+ if zab_cond[c_type] != str(user_cond[c_type]) or zab_cond[_op] != str(user_cond[_op]) or \
+ zab_cond[val] != str(user_cond[val]):
+ return False
+
+ return True
+
+def filter_differences(zabbix_filters, user_filters):
+ '''Determine the differences from user and zabbix for operations'''
+ rval = {}
+ for key, val in user_filters.items():
+
+ if key == 'conditions':
+ if not conditions_equal(zabbix_filters[key], val):
+ rval[key] = val
+
+ elif zabbix_filters[key] != str(val):
+ rval[key] = val
+
+ return rval
+
+# This logic is quite complex. We are comparing two lists of dictionaries.
+# The outer for-loops allow us to descend down into both lists at the same time
+# and then walk over the key,val pairs of the incoming user dict's changes
+# or updates. The if-statements are looking at different sub-object types and
+# comparing them. The other suggestion on how to write this is to write a recursive
+# compare function but for the time constraints and for complexity I decided to go
+# this route.
+# pylint: disable=too-many-branches
+def operation_differences(zabbix_ops, user_ops):
+ '''Determine the differences from user and zabbix for operations'''
+
+ # if they don't match, take the user options
+ if len(zabbix_ops) != len(user_ops):
+ return user_ops
+
+ rval = {}
+ for zab, user in zip(zabbix_ops, user_ops):
+ for key, val in user.items():
+ if key == 'opconditions':
+ for z_cond, u_cond in zip(zab[key], user[key]):
+ if not all([str(u_cond[op_key]) == z_cond[op_key] for op_key in \
+ ['conditiontype', 'operator', 'value']]):
+ rval[key] = val
+ break
+ elif key == 'opmessage':
+ # Verify each passed param matches
+ for op_msg_key, op_msg_val in val.items():
+ if zab[key][op_msg_key] != str(op_msg_val):
+ rval[key] = val
+ break
+
+ elif key == 'opmessage_grp':
+ zab_grp_ids = set([ugrp['usrgrpid'] for ugrp in zab[key]])
+ usr_grp_ids = set([ugrp['usrgrpid'] for ugrp in val])
+ if usr_grp_ids != zab_grp_ids:
+ rval[key] = val
+
+ elif key == 'opmessage_usr':
+ zab_usr_ids = set([usr['userid'] for usr in zab[key]])
+ usr_ids = set([usr['userid'] for usr in val])
+ if usr_ids != zab_usr_ids:
+ rval[key] = val
+
+ elif zab[key] != str(val):
+ rval[key] = val
+ return rval
+
+def get_users(zapi, users):
+ '''get the mediatype id from the mediatype name'''
+ rval_users = []
+
+ for user in users:
+ content = zapi.get_content('user',
+ 'get',
+ {'filter': {'alias': user}})
+ rval_users.append({'userid': content['result'][0]['userid']})
+
+ return rval_users
+
+def get_user_groups(zapi, groups):
+ '''get the mediatype id from the mediatype name'''
+ user_groups = []
+
+ content = zapi.get_content('usergroup',
+ 'get',
+ {'search': {'name': groups}})
+
+ for usr_grp in content['result']:
+ user_groups.append({'usrgrpid': usr_grp['usrgrpid']})
+
+ return user_groups
+
+def get_mediatype_id_by_name(zapi, m_name):
+ '''get the mediatype id from the mediatype name'''
+ content = zapi.get_content('mediatype',
+ 'get',
+ {'filter': {'description': m_name}})
+
+ return content['result'][0]['mediatypeid']
+
+def get_priority(priority):
+ ''' determine priority
+ '''
+ prior = 0
+ if 'info' in priority:
+ prior = 1
+ elif 'warn' in priority:
+ prior = 2
+ elif 'avg' == priority or 'ave' in priority:
+ prior = 3
+ elif 'high' in priority:
+ prior = 4
+ elif 'dis' in priority:
+ prior = 5
+
+ return prior
+
+def get_event_source(from_src):
+ '''Translate even str into value'''
+ choices = ['trigger', 'discovery', 'auto', 'internal']
+ rval = 0
+ try:
+ rval = choices.index(from_src)
+ except ValueError as _:
+ ZabbixAPIError('Value not found for event source [%s]' % from_src)
+
+ return rval
+
+def get_status(inc_status):
+ '''determine status for action'''
+ rval = 1
+ if inc_status == 'enabled':
+ rval = 0
+
+ return rval
+
+def get_condition_operator(inc_operator):
+ ''' determine the condition operator'''
+ vals = {'=': 0,
+ '<>': 1,
+ 'like': 2,
+ 'not like': 3,
+ 'in': 4,
+ '>=': 5,
+ '<=': 6,
+ 'not in': 7,
+ }
+
+ return vals[inc_operator]
+
+def get_host_id_by_name(zapi, host_name):
+ '''Get host id by name'''
+ content = zapi.get_content('host',
+ 'get',
+ {'filter': {'name': host_name}})
+
+ return content['result'][0]['hostid']
+
+def get_trigger_value(inc_trigger):
+ '''determine the proper trigger value'''
+ rval = 1
+ if inc_trigger == 'PROBLEM':
+ rval = 1
+ else:
+ rval = 0
+
+ return rval
+
+def get_template_id_by_name(zapi, t_name):
+ '''get the template id by name'''
+ content = zapi.get_content('template',
+ 'get',
+ {'filter': {'host': t_name}})
+
+ return content['result'][0]['templateid']
+
+
+def get_host_group_id_by_name(zapi, hg_name):
+ '''Get hostgroup id by name'''
+ content = zapi.get_content('hostgroup',
+ 'get',
+ {'filter': {'name': hg_name}})
+
+ return content['result'][0]['groupid']
+
+def get_condition_type(event_source, inc_condition):
+ '''determine the condition type'''
+ c_types = {}
+ if event_source == 'trigger':
+ c_types = {'host group': 0,
+ 'host': 1,
+ 'trigger': 2,
+ 'trigger name': 3,
+ 'trigger severity': 4,
+ 'trigger value': 5,
+ 'time period': 6,
+ 'host template': 13,
+ 'application': 15,
+ 'maintenance status': 16,
+ }
+
+ elif event_source == 'discovery':
+ c_types = {'host IP': 7,
+ 'discovered service type': 8,
+ 'discovered service port': 9,
+ 'discovery status': 10,
+ 'uptime or downtime duration': 11,
+ 'received value': 12,
+ 'discovery rule': 18,
+ 'discovery check': 19,
+ 'proxy': 20,
+ 'discovery object': 21,
+ }
+
+ elif event_source == 'auto':
+ c_types = {'proxy': 20,
+ 'host name': 22,
+ 'host metadata': 24,
+ }
+
+ elif event_source == 'internal':
+ c_types = {'host group': 0,
+ 'host': 1,
+ 'host template': 13,
+ 'application': 15,
+ 'event type': 23,
+ }
+ else:
+ raise ZabbixAPIError('Unkown event source %s' % event_source)
+
+ return c_types[inc_condition]
+
+def get_operation_type(inc_operation):
+ ''' determine the correct operation type'''
+ o_types = {'send message': 0,
+ 'remote command': 1,
+ 'add host': 2,
+ 'remove host': 3,
+ 'add to host group': 4,
+ 'remove from host group': 5,
+ 'link to template': 6,
+ 'unlink from template': 7,
+ 'enable host': 8,
+ 'disable host': 9,
+ }
+
+ return o_types[inc_operation]
+
+def get_action_operations(zapi, inc_operations):
+ '''Convert the operations into syntax for api'''
+ for operation in inc_operations:
+ operation['operationtype'] = get_operation_type(operation['operationtype'])
+ if operation['operationtype'] == 0: # send message. Need to fix the
+ operation['opmessage']['mediatypeid'] = \
+ get_mediatype_id_by_name(zapi, operation['opmessage']['mediatypeid'])
+ operation['opmessage_grp'] = get_user_groups(zapi, operation.get('opmessage_grp', []))
+ operation['opmessage_usr'] = get_users(zapi, operation.get('opmessage_usr', []))
+ if operation['opmessage']['default_msg']:
+ operation['opmessage']['default_msg'] = 1
+ else:
+ operation['opmessage']['default_msg'] = 0
+
+ # NOT supported for remote commands
+ elif operation['operationtype'] == 1:
+ continue
+
+ # Handle Operation conditions:
+ # Currently there is only 1 available which
+ # is 'event acknowledged'. In the future
+ # if there are any added we will need to pass this
+ # option to a function and return the correct conditiontype
+ if operation.has_key('opconditions'):
+ for condition in operation['opconditions']:
+ if condition['conditiontype'] == 'event acknowledged':
+ condition['conditiontype'] = 14
+
+ if condition['operator'] == '=':
+ condition['operator'] = 0
+
+ if condition['value'] == 'acknowledged':
+ condition['operator'] = 1
+ else:
+ condition['operator'] = 0
+
+
+ return inc_operations
+
+def get_operation_evaltype(inc_type):
+ '''get the operation evaltype'''
+ rval = 0
+ if inc_type == 'and/or':
+ rval = 0
+ elif inc_type == 'and':
+ rval = 1
+ elif inc_type == 'or':
+ rval = 2
+ elif inc_type == 'custom':
+ rval = 3
+
+ return rval
+
+def get_action_conditions(zapi, event_source, inc_conditions):
+ '''Convert the conditions into syntax for api'''
+
+ calc_type = inc_conditions.pop('calculation_type')
+ inc_conditions['evaltype'] = get_operation_evaltype(calc_type)
+ for cond in inc_conditions['conditions']:
+
+ cond['operator'] = get_condition_operator(cond['operator'])
+ # Based on conditiontype we need to set the proper value
+ # e.g. conditiontype = hostgroup then the value needs to be a hostgroup id
+ # e.g. conditiontype = host the value needs to be a host id
+ cond['conditiontype'] = get_condition_type(event_source, cond['conditiontype'])
+ if cond['conditiontype'] == 0:
+ cond['value'] = get_host_group_id_by_name(zapi, cond['value'])
+ elif cond['conditiontype'] == 1:
+ cond['value'] = get_host_id_by_name(zapi, cond['value'])
+ elif cond['conditiontype'] == 4:
+ cond['value'] = get_priority(cond['value'])
+
+ elif cond['conditiontype'] == 5:
+ cond['value'] = get_trigger_value(cond['value'])
+ elif cond['conditiontype'] == 13:
+ cond['value'] = get_template_id_by_name(zapi, cond['value'])
+ elif cond['conditiontype'] == 16:
+ cond['value'] = ''
+
+ return inc_conditions
+
+
+def get_send_recovery(send_recovery):
+ '''Get the integer value'''
+ rval = 0
+ if send_recovery:
+ rval = 1
+
+ return rval
+
+# The branches are needed for CRUD and error handling
+# pylint: disable=too-many-branches
+def main():
+ '''
+ ansible zabbix module for zbx_item
+ '''
+
+
+ module = AnsibleModule(
+ argument_spec=dict(
+ zbx_server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'),
+ zbx_user=dict(default=os.environ.get('ZABBIX_USER', None), type='str'),
+ zbx_password=dict(default=os.environ.get('ZABBIX_PASSWORD', None), type='str'),
+ zbx_debug=dict(default=False, type='bool'),
+
+ name=dict(default=None, type='str'),
+ event_source=dict(default='trigger', choices=['trigger', 'discovery', 'auto', 'internal'], type='str'),
+ action_subject=dict(default="{TRIGGER.NAME}: {TRIGGER.STATUS}", type='str'),
+ action_message=dict(default="{TRIGGER.NAME}: {TRIGGER.STATUS}\r\n" +
+ "Last value: {ITEM.LASTVALUE}\r\n\r\n{TRIGGER.URL}", type='str'),
+ reply_subject=dict(default="{TRIGGER.NAME}: {TRIGGER.STATUS}", type='str'),
+ reply_message=dict(default="Trigger: {TRIGGER.NAME}\r\nTrigger status: {TRIGGER.STATUS}\r\n" +
+ "Trigger severity: {TRIGGER.SEVERITY}\r\nTrigger URL: {TRIGGER.URL}\r\n\r\n" +
+ "Item values:\r\n\r\n1. {ITEM.NAME1} ({HOST.NAME1}:{ITEM.KEY1}): " +
+ "{ITEM.VALUE1}\r\n2. {ITEM.NAME2} ({HOST.NAME2}:{ITEM.KEY2}): " +
+ "{ITEM.VALUE2}\r\n3. {ITEM.NAME3} ({HOST.NAME3}:{ITEM.KEY3}): " +
+ "{ITEM.VALUE3}", type='str'),
+ send_recovery=dict(default=False, type='bool'),
+ status=dict(default=None, type='str'),
+ escalation_time=dict(default=60, type='int'),
+ conditions_filter=dict(default=None, type='dict'),
+ operations=dict(default=None, type='list'),
+ state=dict(default='present', type='str'),
+ ),
+ #supports_check_mode=True
+ )
+
+ zapi = ZabbixAPI(ZabbixConnection(module.params['zbx_server'],
+ module.params['zbx_user'],
+ module.params['zbx_password'],
+ module.params['zbx_debug']))
+
+ #Set the instance and the template for the rest of the calls
+ zbx_class_name = 'action'
+ state = module.params['state']
+
+ content = zapi.get_content(zbx_class_name,
+ 'get',
+ {'search': {'name': module.params['name']},
+ 'selectFilter': 'extend',
+ 'selectOperations': 'extend',
+ })
+
+ #******#
+ # GET
+ #******#
+ if state == 'list':
+ module.exit_json(changed=False, results=content['result'], state="list")
+
+ #******#
+ # DELETE
+ #******#
+ if state == 'absent':
+ if not exists(content):
+ module.exit_json(changed=False, state="absent")
+
+ content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0]['itemid']])
+ module.exit_json(changed=True, results=content['result'], state="absent")
+
+ # Create and Update
+ if state == 'present':
+
+ conditions = get_action_conditions(zapi, module.params['event_source'], module.params['conditions_filter'])
+ operations = get_action_operations(zapi, module.params['operations'])
+ params = {'name': module.params['name'],
+ 'esc_period': module.params['escalation_time'],
+ 'eventsource': get_event_source(module.params['event_source']),
+ 'status': get_status(module.params['status']),
+ 'def_shortdata': module.params['action_subject'],
+ 'def_longdata': module.params['action_message'],
+ 'r_shortdata': module.params['reply_subject'],
+ 'r_longdata': module.params['reply_message'],
+ 'recovery_msg': get_send_recovery(module.params['send_recovery']),
+ 'filter': conditions,
+ 'operations': operations,
+ }
+
+ # Remove any None valued params
+ _ = [params.pop(key, None) for key in params.keys() if params[key] is None]
+
+ #******#
+ # CREATE
+ #******#
+ if not exists(content):
+ content = zapi.get_content(zbx_class_name, 'create', params)
+
+ if content.has_key('error'):
+ module.exit_json(failed=True, changed=True, results=content['error'], state="present")
+
+ module.exit_json(changed=True, results=content['result'], state='present')
+
+
+ ########
+ # UPDATE
+ ########
+ _ = params.pop('hostid', None)
+ differences = {}
+ zab_results = content['result'][0]
+ for key, value in params.items():
+
+ if key == 'operations':
+ ops = operation_differences(zab_results[key], value)
+ if ops:
+ differences[key] = ops
+
+ elif key == 'filter':
+ filters = filter_differences(zab_results[key], value)
+ if filters:
+ differences[key] = filters
+
+ elif zab_results[key] != value and zab_results[key] != str(value):
+ differences[key] = value
+
+ if not differences:
+ module.exit_json(changed=False, results=zab_results, state="present")
+
+ # We have differences and need to update.
+ # action update requires an id, filters, and operations
+ differences['actionid'] = zab_results['actionid']
+ differences['operations'] = params['operations']
+ differences['filter'] = params['filter']
+ content = zapi.get_content(zbx_class_name, 'update', differences)
+
+ if content.has_key('error'):
+ module.exit_json(failed=True, changed=False, results=content['error'], state="present")
+
+ module.exit_json(changed=True, results=content['result'], state="present")
+
+ module.exit_json(failed=True,
+ changed=False,
+ results='Unknown state passed. %s' % state,
+ state="unknown")
+
+# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled
+# import module snippets. This are required
+from ansible.module_utils.basic import *
+
+main()
diff --git a/roles/lib_zabbix/library/zbx_discoveryrule.py b/roles/lib_zabbix/library/zbx_discoveryrule.py
index 71a0580c2..f52f350a5 100644
--- a/roles/lib_zabbix/library/zbx_discoveryrule.py
+++ b/roles/lib_zabbix/library/zbx_discoveryrule.py
@@ -85,6 +85,7 @@ def main():
Ansible module for zabbix discovery rules
'''
+
module = AnsibleModule(
argument_spec=dict(
zbx_server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'),
@@ -93,6 +94,7 @@ def main():
zbx_debug=dict(default=False, type='bool'),
name=dict(default=None, type='str'),
key=dict(default=None, type='str'),
+ description=dict(default=None, type='str'),
interfaceid=dict(default=None, type='int'),
ztype=dict(default='trapper', type='str'),
delay=dict(default=60, type='int'),
@@ -113,18 +115,27 @@ def main():
idname = "itemid"
dname = module.params['name']
state = module.params['state']
+ template = get_template(zapi, module.params['template_name'])
# selectInterfaces doesn't appear to be working but is needed.
content = zapi.get_content(zbx_class_name,
'get',
{'search': {'name': dname},
+ 'templateids': template['templateid'],
#'selectDServices': 'extend',
#'selectDChecks': 'extend',
#'selectDhosts': 'dhostid',
})
+
+ #******#
+ # GET
+ #******#
if state == 'list':
module.exit_json(changed=False, results=content['result'], state="list")
+ #******#
+ # DELETE
+ #******#
if state == 'absent':
if not exists(content):
module.exit_json(changed=False, state="absent")
@@ -132,24 +143,37 @@ def main():
content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]])
module.exit_json(changed=True, results=content['result'], state="absent")
+
+ # Create and Update
if state == 'present':
- template = get_template(zapi, module.params['template_name'])
params = {'name': dname,
'key_': module.params['key'],
'hostid': template['templateid'],
'interfaceid': module.params['interfaceid'],
'lifetime': module.params['lifetime'],
'type': get_type(module.params['ztype']),
+ 'description': module.params['description'],
}
if params['type'] in [2, 5, 7, 11]:
params.pop('interfaceid')
+ # Remove any None valued params
+ _ = [params.pop(key, None) for key in params.keys() if params[key] is None]
+
+ #******#
+ # CREATE
+ #******#
if not exists(content):
- # if we didn't find it, create it
content = zapi.get_content(zbx_class_name, 'create', params)
+
+ if content.has_key('error'):
+ module.exit_json(failed=True, changed=True, results=content['error'], state="present")
+
module.exit_json(changed=True, results=content['result'], state='present')
- # already exists, we need to update it
- # let's compare properties
+
+ ########
+ # UPDATE
+ ########
differences = {}
zab_results = content['result'][0]
for key, value in params.items():
@@ -163,6 +187,10 @@ def main():
# We have differences and need to update
differences[idname] = zab_results[idname]
content = zapi.get_content(zbx_class_name, 'update', differences)
+
+ if content.has_key('error'):
+ module.exit_json(failed=True, changed=False, results=content['error'], state="present")
+
module.exit_json(changed=True, results=content['result'], state="present")
module.exit_json(failed=True,
diff --git a/roles/lib_zabbix/library/zbx_itemprototype.py b/roles/lib_zabbix/library/zbx_itemprototype.py
index 24f85710d..4ec1b8e02 100644
--- a/roles/lib_zabbix/library/zbx_itemprototype.py
+++ b/roles/lib_zabbix/library/zbx_itemprototype.py
@@ -38,13 +38,14 @@ def exists(content, key='result'):
return True
-def get_rule_id(zapi, discoveryrule_name):
+def get_rule_id(zapi, discoveryrule_key, templateid):
'''get a discoveryrule by name
'''
content = zapi.get_content('discoveryrule',
'get',
- {'search': {'name': discoveryrule_name},
+ {'search': {'key_': discoveryrule_key},
'output': 'extend',
+ 'templateids': templateid,
})
if not content['result']:
return None
@@ -53,6 +54,9 @@ def get_rule_id(zapi, discoveryrule_name):
def get_template(zapi, template_name):
'''get a template by name
'''
+ if not template_name:
+ return None
+
content = zapi.get_content('template',
'get',
{'search': {'host': template_name},
@@ -134,6 +138,7 @@ def get_app_ids(zapi, application_names):
app_ids.append(content['result'][0]['applicationid'])
return app_ids
+# pylint: disable=too-many-branches
def main():
'''
Ansible module for zabbix discovery rules
@@ -147,16 +152,17 @@ def main():
zbx_debug=dict(default=False, type='bool'),
name=dict(default=None, type='str'),
key=dict(default=None, type='str'),
+ description=dict(default=None, type='str'),
interfaceid=dict(default=None, type='int'),
ztype=dict(default='trapper', type='str'),
value_type=dict(default='float', type='str'),
delay=dict(default=60, type='int'),
lifetime=dict(default=30, type='int'),
- template_name=dict(default=[], type='list'),
state=dict(default='present', type='str'),
status=dict(default='enabled', type='str'),
- discoveryrule_name=dict(default=None, type='str'),
applications=dict(default=[], type='list'),
+ template_name=dict(default=None, type='str'),
+ discoveryrule_key=dict(default=None, type='str'),
),
#supports_check_mode=True
)
@@ -169,20 +175,27 @@ def main():
#Set the instance and the template for the rest of the calls
zbx_class_name = 'itemprototype'
idname = "itemid"
- dname = module.params['name']
state = module.params['state']
+ template = get_template(zapi, module.params['template_name'])
# selectInterfaces doesn't appear to be working but is needed.
content = zapi.get_content(zbx_class_name,
'get',
- {'search': {'name': dname},
+ {'search': {'key_': module.params['key']},
'selectApplications': 'applicationid',
'selectDiscoveryRule': 'itemid',
- #'selectDhosts': 'dhostid',
+ 'templated': True,
})
+
+ #******#
+ # GET
+ #******#
if state == 'list':
module.exit_json(changed=False, results=content['result'], state="list")
+ #******#
+ # DELETE
+ #******#
if state == 'absent':
if not exists(content):
module.exit_json(changed=False, state="absent")
@@ -190,26 +203,39 @@ def main():
content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]])
module.exit_json(changed=True, results=content['result'], state="absent")
+ # Create and Update
if state == 'present':
- template = get_template(zapi, module.params['template_name'])
- params = {'name': dname,
+ params = {'name': module.params['name'],
'key_': module.params['key'],
'hostid': template['templateid'],
'interfaceid': module.params['interfaceid'],
- 'ruleid': get_rule_id(zapi, module.params['discoveryrule_name']),
+ 'ruleid': get_rule_id(zapi, module.params['discoveryrule_key'], template['templateid']),
'type': get_type(module.params['ztype']),
'value_type': get_value_type(module.params['value_type']),
'applications': get_app_ids(zapi, module.params['applications']),
+ 'description': module.params['description'],
}
+
if params['type'] in [2, 5, 7, 8, 11, 15]:
params.pop('interfaceid')
+ # Remove any None valued params
+ _ = [params.pop(key, None) for key in params.keys() if params[key] is None]
+
+ #******#
+ # CREATE
+ #******#
if not exists(content):
- # if we didn't find it, create it
content = zapi.get_content(zbx_class_name, 'create', params)
+
+ if content.has_key('error'):
+ module.exit_json(failed=True, changed=False, results=content['error'], state="present")
+
module.exit_json(changed=True, results=content['result'], state='present')
- # already exists, we need to update it
- # let's compare properties
+
+ #******#
+ # UPDATE
+ #******#
differences = {}
zab_results = content['result'][0]
for key, value in params.items():
@@ -218,6 +244,11 @@ def main():
if value != zab_results['discoveryRule']['itemid']:
differences[key] = value
+ elif key == 'applications':
+ app_ids = [app['applicationid'] for app in zab_results[key]]
+ if set(app_ids) - set(value):
+ differences[key] = value
+
elif zab_results[key] != value and zab_results[key] != str(value):
differences[key] = value
@@ -227,6 +258,10 @@ def main():
# We have differences and need to update
differences[idname] = zab_results[idname]
content = zapi.get_content(zbx_class_name, 'update', differences)
+
+ if content.has_key('error'):
+ module.exit_json(failed=True, changed=False, results=content['error'], state="present")
+
module.exit_json(changed=True, results=content['result'], state="present")
module.exit_json(failed=True,
diff --git a/roles/lib_zabbix/library/zbx_trigger.py b/roles/lib_zabbix/library/zbx_trigger.py
index a05de7e68..21d0fcfd2 100644
--- a/roles/lib_zabbix/library/zbx_trigger.py
+++ b/roles/lib_zabbix/library/zbx_trigger.py
@@ -74,6 +74,18 @@ def get_deps(zapi, deps):
return results
+
+def get_trigger_status(inc_status):
+ ''' Determine the trigger's status
+ 0 is enabled
+ 1 is disabled
+ '''
+ r_status = 0
+ if inc_status == 'disabled':
+ r_status = 1
+
+ return r_status
+
def main():
'''
Create a trigger in zabbix
@@ -103,6 +115,7 @@ def main():
dependencies=dict(default=[], type='list'),
priority=dict(default='avg', type='str'),
url=dict(default=None, type='str'),
+ status=dict(default=None, type='str'),
state=dict(default='present', type='str'),
),
#supports_check_mode=True
@@ -145,6 +158,7 @@ def main():
'dependencies': get_deps(zapi, module.params['dependencies']),
'priority': get_priority(module.params['priority']),
'url': module.params['url'],
+ 'status': get_trigger_status(module.params['status']),
}
# Remove any None valued params
@@ -156,6 +170,10 @@ def main():
if not exists(content):
# if we didn't find it, create it
content = zapi.get_content(zbx_class_name, 'create', params)
+
+ if content.has_key('error'):
+ module.exit_json(failed=True, changed=True, results=content['error'], state="present")
+
module.exit_json(changed=True, results=content['result'], state='present')
########
diff --git a/roles/lib_zabbix/library/zbx_triggerprototype.py b/roles/lib_zabbix/library/zbx_triggerprototype.py
new file mode 100644
index 000000000..c1224b268
--- /dev/null
+++ b/roles/lib_zabbix/library/zbx_triggerprototype.py
@@ -0,0 +1,177 @@
+#!/usr/bin/env python
+'''
+ansible module for zabbix triggerprototypes
+'''
+# vim: expandtab:tabstop=4:shiftwidth=4
+#
+# Zabbix triggerprototypes ansible module
+#
+#
+# Copyright 2015 Red Hat Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This is in place because each module looks similar to each other.
+# These need duplicate code as their behavior is very similar
+# but different for each zabbix class.
+# pylint: disable=duplicate-code
+
+# pylint: disable=import-error
+from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection
+
+def exists(content, key='result'):
+ ''' Check if key exists in content or the size of content[key] > 0
+ '''
+ if not content.has_key(key):
+ return False
+
+ if not content[key]:
+ return False
+
+ return True
+
+def get_priority(priority):
+ ''' determine priority
+ '''
+ prior = 0
+ if 'info' in priority:
+ prior = 1
+ elif 'warn' in priority:
+ prior = 2
+ elif 'avg' == priority or 'ave' in priority:
+ prior = 3
+ elif 'high' in priority:
+ prior = 4
+ elif 'dis' in priority:
+ prior = 5
+
+ return prior
+
+def get_trigger_status(inc_status):
+ ''' Determine the trigger's status
+ 0 is enabled
+ 1 is disabled
+ '''
+ r_status = 0
+ if inc_status == 'disabled':
+ r_status = 1
+
+ return r_status
+
+
+def main():
+ '''
+ Create a triggerprototype in zabbix
+ '''
+
+ module = AnsibleModule(
+ argument_spec=dict(
+ zbx_server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'),
+ zbx_user=dict(default=os.environ.get('ZABBIX_USER', None), type='str'),
+ zbx_password=dict(default=os.environ.get('ZABBIX_PASSWORD', None), type='str'),
+ zbx_debug=dict(default=False, type='bool'),
+ name=dict(default=None, type='str'),
+ expression=dict(default=None, type='str'),
+ description=dict(default=None, type='str'),
+ priority=dict(default='avg', type='str'),
+ url=dict(default=None, type='str'),
+ status=dict(default=None, type='str'),
+ state=dict(default='present', type='str'),
+ ),
+ #supports_check_mode=True
+ )
+
+ zapi = ZabbixAPI(ZabbixConnection(module.params['zbx_server'],
+ module.params['zbx_user'],
+ module.params['zbx_password'],
+ module.params['zbx_debug']))
+
+ #Set the instance and the template for the rest of the calls
+ zbx_class_name = 'triggerprototype'
+ idname = "triggerid"
+ state = module.params['state']
+ tname = module.params['name']
+
+ content = zapi.get_content(zbx_class_name,
+ 'get',
+ {'filter': {'description': tname},
+ 'expandExpression': True,
+ 'selectDependencies': 'triggerid',
+ })
+
+ # Get
+ if state == 'list':
+ module.exit_json(changed=False, results=content['result'], state="list")
+
+ # Delete
+ if state == 'absent':
+ if not exists(content):
+ module.exit_json(changed=False, state="absent")
+ content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]])
+ module.exit_json(changed=True, results=content['result'], state="absent")
+
+ # Create and Update
+ if state == 'present':
+ params = {'description': tname,
+ 'comments': module.params['description'],
+ 'expression': module.params['expression'],
+ 'priority': get_priority(module.params['priority']),
+ 'url': module.params['url'],
+ 'status': get_trigger_status(module.params['status']),
+ }
+
+ # Remove any None valued params
+ _ = [params.pop(key, None) for key in params.keys() if params[key] is None]
+
+ #******#
+ # CREATE
+ #******#
+ if not exists(content):
+ # if we didn't find it, create it
+ content = zapi.get_content(zbx_class_name, 'create', params)
+
+ if content.has_key('error'):
+ module.exit_json(failed=True, changed=True, results=content['error'], state="present")
+
+ module.exit_json(changed=True, results=content['result'], state='present')
+
+ ########
+ # UPDATE
+ ########
+ differences = {}
+ zab_results = content['result'][0]
+ for key, value in params.items():
+
+ if zab_results[key] != value and zab_results[key] != str(value):
+ differences[key] = value
+
+ if not differences:
+ module.exit_json(changed=False, results=zab_results, state="present")
+
+ # We have differences and need to update
+ differences[idname] = zab_results[idname]
+ content = zapi.get_content(zbx_class_name, 'update', differences)
+ module.exit_json(changed=True, results=content['result'], state="present")
+
+
+ module.exit_json(failed=True,
+ changed=False,
+ results='Unknown state passed. %s' % state,
+ state="unknown")
+
+# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled
+# import module snippets. This are required
+from ansible.module_utils.basic import *
+
+main()
diff --git a/roles/lib_zabbix/library/zbx_user_media.py b/roles/lib_zabbix/library/zbx_user_media.py
index 3f7760475..9ed838f81 100644
--- a/roles/lib_zabbix/library/zbx_user_media.py
+++ b/roles/lib_zabbix/library/zbx_user_media.py
@@ -54,8 +54,8 @@ def get_mtype(zapi, mtype):
except ValueError:
pass
- content = zapi.get_content('mediatype', 'get', {'search': {'description': mtype}})
- if content.has_key['result'] and content['result']:
+ content = zapi.get_content('mediatype', 'get', {'filter': {'description': mtype}})
+ if content.has_key('result') and content['result']:
return content['result'][0]['mediatypeid']
return None
@@ -63,7 +63,7 @@ def get_mtype(zapi, mtype):
def get_user(zapi, user):
''' Get userids from user aliases
'''
- content = zapi.get_content('user', 'get', {'search': {'alias': user}})
+ content = zapi.get_content('user', 'get', {'filter': {'alias': user}})
if content['result']:
return content['result'][0]
@@ -104,15 +104,17 @@ def find_media(medias, user_media):
''' Find the user media in the list of medias
'''
for media in medias:
- if all([media[key] == user_media[key] for key in user_media.keys()]):
+ if all([media[key] == str(user_media[key]) for key in user_media.keys()]):
return media
return None
-def get_active(in_active):
+def get_active(is_active):
'''Determine active value
+ 0 - enabled
+ 1 - disabled
'''
active = 1
- if in_active:
+ if is_active:
active = 0
return active
@@ -128,6 +130,21 @@ def get_mediatype(zapi, mediatype, mediatype_desc):
return mtypeid
+def preprocess_medias(zapi, medias):
+ ''' Insert the correct information when processing medias '''
+ for media in medias:
+ # Fetch the mediatypeid from the media desc (name)
+ if media.has_key('mediatype'):
+ media['mediatypeid'] = get_mediatype(zapi, mediatype=None, mediatype_desc=media.pop('mediatype'))
+
+ media['active'] = get_active(media.get('active'))
+ media['severity'] = int(get_severity(media['severity']))
+
+ return medias
+
+# Disabling branching as the logic requires branches.
+# I've also added a few safeguards which required more branches.
+# pylint: disable=too-many-branches
def main():
'''
Ansible zabbix module for mediatype
@@ -166,11 +183,17 @@ def main():
# User media is fetched through the usermedia.get
zbx_user_query = get_zbx_user_query_data(zapi, module.params['login'])
- content = zapi.get_content('usermedia', 'get', zbx_user_query)
-
+ content = zapi.get_content('usermedia', 'get',
+ {'userids': [uid for user, uid in zbx_user_query.items()]})
+ #####
+ # Get
+ #####
if state == 'list':
module.exit_json(changed=False, results=content['result'], state="list")
+ ########
+ # Delete
+ ########
if state == 'absent':
if not exists(content) or len(content['result']) == 0:
module.exit_json(changed=False, state="absent")
@@ -178,13 +201,14 @@ def main():
if not module.params['login']:
module.exit_json(failed=True, changed=False, results='Must specifiy a user login.', state="absent")
- content = zapi.get_content(zbx_class_name, 'deletemedia', [content['result'][0][idname]])
+ content = zapi.get_content(zbx_class_name, 'deletemedia', [res[idname] for res in content['result']])
if content.has_key('error'):
module.exit_json(changed=False, results=content['error'], state="absent")
module.exit_json(changed=True, results=content['result'], state="absent")
+ # Create and Update
if state == 'present':
active = get_active(module.params['active'])
mtypeid = get_mediatype(zapi, module.params['mediatype'], module.params['mediatype_desc'])
@@ -197,13 +221,21 @@ def main():
'severity': int(get_severity(module.params['severity'])),
'period': module.params['period'],
}]
+ else:
+ medias = preprocess_medias(zapi, medias)
params = {'users': [zbx_user_query],
'medias': medias,
'output': 'extend',
}
+ ########
+ # Create
+ ########
if not exists(content):
+ if not params['medias']:
+ module.exit_json(changed=False, results=content['result'], state='present')
+
# if we didn't find it, create it
content = zapi.get_content(zbx_class_name, 'addmedia', params)
@@ -216,6 +248,9 @@ def main():
# If user params exists, check to see if they already exist in zabbix
# if they exist, then return as no update
# elif they do not exist, then take user params only
+ ########
+ # Update
+ ########
diff = {'medias': [], 'users': {}}
_ = [diff['medias'].append(media) for media in params['medias'] if not find_media(content['result'], media)]
diff --git a/roles/lib_zabbix/tasks/create_template.yml b/roles/lib_zabbix/tasks/create_template.yml
index fd0cdd46f..62259b680 100644
--- a/roles/lib_zabbix/tasks/create_template.yml
+++ b/roles/lib_zabbix/tasks/create_template.yml
@@ -52,3 +52,44 @@
url: "{{ item.url | default(None, True) }}"
with_items: template.ztriggers
when: template.ztriggers is defined
+
+- name: Create Discoveryrules
+ zbx_discoveryrule:
+ zbx_server: "{{ server }}"
+ zbx_user: "{{ user }}"
+ zbx_password: "{{ password }}"
+ name: "{{ item.name }}"
+ key: "{{ item.key }}"
+ lifetime: "{{ item.lifetime }}"
+ template_name: "{{ template.name }}"
+ description: "{{ item.description | default('', True) }}"
+ with_items: template.zdiscoveryrules
+ when: template.zdiscoveryrules is defined
+
+- name: Create Item Prototypes
+ zbx_itemprototype:
+ zbx_server: "{{ server }}"
+ zbx_user: "{{ user }}"
+ zbx_password: "{{ password }}"
+ name: "{{ item.name }}"
+ key: "{{ item.key }}"
+ discoveryrule_key: "{{ item.discoveryrule_key }}"
+ value_type: "{{ item.value_type }}"
+ template_name: "{{ template.name }}"
+ applications: "{{ item.applications }}"
+ description: "{{ item.description | default('', True) }}"
+ with_items: template.zitemprototypes
+ when: template.zitemprototypes is defined
+
+- name: Create Trigger Prototypes
+ zbx_triggerprototype:
+ zbx_server: "{{ server }}"
+ zbx_user: "{{ user }}"
+ zbx_password: "{{ password }}"
+ name: "{{ item.name }}"
+ expression: "{{ item.expression }}"
+ url: "{{ item.url | default('', True) }}"
+ priority: "{{ item.priority | default('average', True) }}"
+ description: "{{ item.description | default('', True) }}"
+ with_items: template.ztriggerprototypes
+ when: template.ztriggerprototypes is defined
diff --git a/roles/openshift_facts/library/openshift_facts.py b/roles/openshift_facts/library/openshift_facts.py
index 991b8da66..f708f9bac 100755
--- a/roles/openshift_facts/library/openshift_facts.py
+++ b/roles/openshift_facts/library/openshift_facts.py
@@ -644,7 +644,7 @@ def merge_facts(orig, new):
facts = dict()
for key, value in orig.iteritems():
if key in new:
- if isinstance(value, dict):
+ if isinstance(value, dict) and isinstance(new[key], dict):
facts[key] = merge_facts(value, new[key])
else:
facts[key] = copy.copy(new[key])
diff --git a/roles/os_zabbix/vars/template_os_linux.yml b/roles/os_zabbix/vars/template_os_linux.yml
index 3173c79b2..3c29c5d16 100644
--- a/roles/os_zabbix/vars/template_os_linux.yml
+++ b/roles/os_zabbix/vars/template_os_linux.yml
@@ -191,6 +191,35 @@ g_template_os_linux:
- Disk
value_type: float
+
+ zdiscoveryrules:
+ - name: disc.filesys
+ key: disc.filesys
+ lifetime: 1
+ template_name: Template OS Linux
+ description: "Dynamically register the filesystems"
+
+ zitemprototypes:
+ - discoveryrule_key: disc.filesys
+ template_name: Template OS Linux
+ name: "disc.filesys.full.{#OSO_FILESYS}"
+ key: "disc.filesys.full[{#OSO_FILESYS}]"
+ value_type: float
+ description: "PCP filesys.full option. This is the percent full returned from pcp filesys.full"
+ applications:
+ - Disk
+
+ ztriggerprototypes:
+ - name: 'Filesystem: {#OSO_FILESYS} has less than 10% free on {HOST.NAME}'
+ expression: '{Template OS Linux:disc.filesys.full[{#OSO_FILESYS}].last()}>90'
+ url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/check_filesys_full.asciidoc'
+ priority: warn
+
+ - name: 'Filesystem: {#OSO_FILESYS} has less than 5% free on {HOST.NAME}'
+ expression: '{Template OS Linux:disc.filesys.full[{#OSO_FILESYS}].last()}>95'
+ url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/check_filesys_full.asciidoc'
+ priority: high
+
ztriggers:
- name: 'Filesystem: / has less than 10% free on {HOST.NAME}'
expression: '{Template OS Linux:filesys.full.xvda2.last()}>90'