summaryrefslogtreecommitdiffstats
path: root/roles
diff options
context:
space:
mode:
Diffstat (limited to 'roles')
-rw-r--r--roles/fluentd_master/tasks/main.yml46
-rw-r--r--roles/fluentd_master/templates/kubernetes.conf.j29
-rw-r--r--roles/fluentd_node/tasks/main.yml54
-rw-r--r--roles/fluentd_node/templates/kubernetes.conf.j253
-rw-r--r--roles/fluentd_node/templates/td-agent.j22
-rw-r--r--roles/openshift_common/tasks/main.yml1
-rw-r--r--roles/openshift_master/README.md2
-rw-r--r--roles/openshift_master/defaults/main.yml4
-rw-r--r--roles/openshift_master/tasks/main.yml14
-rw-r--r--roles/openshift_node/README.md2
-rw-r--r--roles/openshift_register_nodes/tasks/main.yml14
-rw-r--r--roles/openshift_registry/README.md42
-rw-r--r--roles/openshift_registry/handlers/main.yml0
-rw-r--r--roles/openshift_registry/meta/main.yml13
-rw-r--r--roles/openshift_registry/tasks/main.yml8
-rw-r--r--roles/openshift_registry/vars/main.yml2
-rw-r--r--roles/openshift_router/README.md41
-rw-r--r--roles/openshift_router/handlers/main.yml0
-rw-r--r--roles/openshift_router/meta/main.yml13
-rw-r--r--roles/openshift_router/tasks/main.yml8
-rw-r--r--roles/openshift_router/vars/main.yml2
-rwxr-xr-xroles/os_zabbix/library/zbxapi.py259
22 files changed, 492 insertions, 97 deletions
diff --git a/roles/fluentd_master/tasks/main.yml b/roles/fluentd_master/tasks/main.yml
new file mode 100644
index 000000000..28caaa5b8
--- /dev/null
+++ b/roles/fluentd_master/tasks/main.yml
@@ -0,0 +1,46 @@
+---
+# TODO: Update fluentd install and configuration when packaging is complete
+- name: download and install td-agent
+ yum:
+ name: 'http://packages.treasuredata.com/2/redhat/7/x86_64/td-agent-2.2.0-0.x86_64.rpm'
+ state: present
+
+- name: Verify fluentd plugin installed
+ command: '/opt/td-agent/embedded/bin/gem query -i fluent-plugin-kubernetes'
+ register: _fluent_plugin_check
+ ignore_errors: yes
+
+- name: install Kubernetes fluentd plugin
+ command: '/opt/td-agent/embedded/bin/gem install fluent-plugin-kubernetes'
+ when: _fluent_plugin_check.rc == 1
+
+- name: Creates directories
+ file:
+ path: "{{ item }}"
+ state: directory
+ group: 'td-agent'
+ owner: 'td-agent'
+ mode: 0755
+ with_items: ['/etc/td-agent/config.d']
+
+- name: Add include to td-agent configuration
+ lineinfile:
+ dest: '/etc/td-agent/td-agent.conf'
+ regexp: '^@include config.d'
+ line: '@include config.d/*.conf'
+ state: present
+
+- name: install Kubernetes fluentd configuration file
+ template:
+ src: kubernetes.conf.j2
+ dest: /etc/td-agent/config.d/kubernetes.conf
+ group: 'td-agent'
+ owner: 'td-agent'
+ mode: 0444
+
+- name: ensure td-agent is running
+ service:
+ name: 'td-agent'
+ state: started
+ enabled: yes
+
diff --git a/roles/fluentd_master/templates/kubernetes.conf.j2 b/roles/fluentd_master/templates/kubernetes.conf.j2
new file mode 100644
index 000000000..7b5c86062
--- /dev/null
+++ b/roles/fluentd_master/templates/kubernetes.conf.j2
@@ -0,0 +1,9 @@
+<match kubernetes.**>
+ type file
+ path /var/log/td-agent/containers.log
+ time_slice_format %Y%m%d
+ time_slice_wait 10m
+ time_format %Y%m%dT%H%M%S%z
+ compress gzip
+ utc
+</match>
diff --git a/roles/fluentd_node/tasks/main.yml b/roles/fluentd_node/tasks/main.yml
new file mode 100644
index 000000000..2526057cb
--- /dev/null
+++ b/roles/fluentd_node/tasks/main.yml
@@ -0,0 +1,54 @@
+---
+# TODO: Update fluentd install and configuration when packaging is complete
+- name: download and install td-agent
+ yum:
+ name: 'http://packages.treasuredata.com/2/redhat/7/x86_64/td-agent-2.2.0-0.x86_64.rpm'
+ state: present
+
+- name: Verify fluentd plugin installed
+ command: '/opt/td-agent/embedded/bin/gem query -i fluent-plugin-kubernetes'
+ register: _fluent_plugin_check
+ ignore_errors: yes
+
+- name: install Kubernetes fluentd plugin
+ command: '/opt/td-agent/embedded/bin/gem install fluent-plugin-kubernetes'
+ when: _fluent_plugin_check.rc == 1
+
+- name: Override td-agent configuration file
+ template:
+ src: td-agent.j2
+ dest: /etc/sysconfig/td-agent
+ group: 'td-agent'
+ owner: 'td-agent'
+ mode: 0444
+
+- name: Creates directories
+ file:
+ path: "{{ item }}"
+ state: directory
+ group: 'td-agent'
+ owner: 'td-agent'
+ mode: 0755
+ with_items: ['/etc/td-agent/config.d', '/var/log/td-agent/tmp']
+
+- name: Add include to td-agent configuration
+ lineinfile:
+ dest: '/etc/td-agent/td-agent.conf'
+ regexp: '^@include config.d'
+ line: '@include config.d/*.conf'
+ state: present
+
+- name: install Kubernetes fluentd configuration file
+ template:
+ src: kubernetes.conf.j2
+ dest: /etc/td-agent/config.d/kubernetes.conf
+ group: 'td-agent'
+ owner: 'td-agent'
+ mode: 0444
+
+- name: ensure td-agent is running
+ service:
+ name: 'td-agent'
+ state: started
+ enabled: yes
+
diff --git a/roles/fluentd_node/templates/kubernetes.conf.j2 b/roles/fluentd_node/templates/kubernetes.conf.j2
new file mode 100644
index 000000000..5f1eecb20
--- /dev/null
+++ b/roles/fluentd_node/templates/kubernetes.conf.j2
@@ -0,0 +1,53 @@
+<source>
+ type tail
+ path /var/lib/docker/containers/*/*-json.log
+ pos_file /var/log/td-agent/tmp/fluentd-docker.pos
+ time_format %Y-%m-%dT%H:%M:%S
+ tag docker.*
+ format json
+ read_from_head true
+</source>
+
+<match docker.var.lib.docker.containers.*.*.log>
+ type kubernetes
+ container_id ${tag_parts[5]}
+ tag docker.${name}
+</match>
+
+<match kubernetes>
+ type copy
+
+ <store>
+ type forward
+ send_timeout 60s
+ recover_wait 10s
+ heartbeat_interval 1s
+ phi_threshold 16
+ hard_timeout 60s
+ log_level trace
+ require_ack_response true
+ heartbeat_type tcp
+
+ <server>
+ name {{groups['oo_first_master'][0]}}
+ host {{hostvars[groups['oo_first_master'][0]].openshift.common.hostname}}
+ port 24224
+ weight 60
+ </server>
+
+ <secondary>
+ type file
+ path /var/log/td-agent/forward-failed
+ </secondary>
+ </store>
+
+ <store>
+ type file
+ path /var/log/td-agent/containers.log
+ time_slice_format %Y%m%d
+ time_slice_wait 10m
+ time_format %Y%m%dT%H%M%S%z
+ compress gzip
+ utc
+ </store>
+</match>
diff --git a/roles/fluentd_node/templates/td-agent.j2 b/roles/fluentd_node/templates/td-agent.j2
new file mode 100644
index 000000000..7245e11ec
--- /dev/null
+++ b/roles/fluentd_node/templates/td-agent.j2
@@ -0,0 +1,2 @@
+DAEMON_ARGS=
+TD_AGENT_ARGS="/usr/sbin/td-agent --log /var/log/td-agent/td-agent.log --use-v1-config"
diff --git a/roles/openshift_common/tasks/main.yml b/roles/openshift_common/tasks/main.yml
index c55677c3f..5bd8690a7 100644
--- a/roles/openshift_common/tasks/main.yml
+++ b/roles/openshift_common/tasks/main.yml
@@ -10,6 +10,7 @@
public_hostname: "{{ openshift_public_hostname | default(None) }}"
public_ip: "{{ openshift_public_ip | default(None) }}"
use_openshift_sdn: "{{ openshift_use_openshift_sdn | default(None) }}"
+ use_fluentd: "{{ openshift_use_fluentd | default(True) }}"
deployment_type: "{{ openshift_deployment_type }}"
- name: Set hostname
hostname: name={{ openshift.common.hostname }}
diff --git a/roles/openshift_master/README.md b/roles/openshift_master/README.md
index 9f9d0a613..3178e318c 100644
--- a/roles/openshift_master/README.md
+++ b/roles/openshift_master/README.md
@@ -17,7 +17,7 @@ From this role:
|-------------------------------------|-----------------------|--------------------------------------------------|
| openshift_master_debug_level | openshift_debug_level | Verbosity of the debug logs for openshift-master |
| openshift_node_ips | [] | List of the openshift node ip addresses to pre-register when openshift-master starts up |
-| openshift_registry_url | UNDEF | Default docker registry to use |
+| oreg_url | UNDEF | Default docker registry to use |
| openshift_master_api_port | UNDEF | |
| openshift_master_console_port | UNDEF | |
| openshift_master_api_url | UNDEF | |
diff --git a/roles/openshift_master/defaults/main.yml b/roles/openshift_master/defaults/main.yml
index 56cf43531..11195e83e 100644
--- a/roles/openshift_master/defaults/main.yml
+++ b/roles/openshift_master/defaults/main.yml
@@ -11,6 +11,10 @@ os_firewall_allow:
port: 53/tcp
- service: OpenShift dns udp
port: 53/udp
+- service: Fluentd td-agent tcp
+ port: 24224/tcp
+- service: Fluentd td-agent udp
+ port: 24224/udp
os_firewall_deny:
- service: OpenShift api http
port: 8080/tcp
diff --git a/roles/openshift_master/tasks/main.yml b/roles/openshift_master/tasks/main.yml
index f9e6199a5..ac96e2b48 100644
--- a/roles/openshift_master/tasks/main.yml
+++ b/roles/openshift_master/tasks/main.yml
@@ -49,15 +49,15 @@
# TODO: should probably use a template lookup for this
# TODO: should allow for setting --etcd, --kubernetes options
# TODO: recreate config if values change
-- name: Use enterprise default for openshift_registry_url if not set
+- name: Use enterprise default for oreg_url if not set
set_fact:
- openshift_registry_url: "openshift3_beta/ose-${component}:${version}"
- when: openshift.common.deployment_type == 'enterprise' and openshift_registry_url is not defined
+ oreg_url: "openshift3_beta/ose-${component}:${version}"
+ when: openshift.common.deployment_type == 'enterprise' and oreg_url is not defined
-- name: Use online default for openshift_registry_url if not set
+- name: Use online default for oreg_url if not set
set_fact:
- openshift_registry_url: "docker-registry.ops.rhcloud.com/openshift3_beta/ose-${component}:${version}"
- when: openshift.common.deployment_type == 'online' and openshift_registry_url is not defined
+ oreg_url: "docker-registry.ops.rhcloud.com/openshift3_beta/ose-${component}:${version}"
+ when: openshift.common.deployment_type == 'online' and oreg_url is not defined
- name: Create master config
command: >
@@ -67,7 +67,7 @@
--master={{ openshift.master.api_url }}
--public-master={{ openshift.master.public_api_url }}
--listen={{ 'https' if openshift.master.api_use_ssl else 'http' }}://0.0.0.0:{{ openshift.master.api_port }}
- {{ ('--images=' ~ openshift_registry_url) if (openshift_registry_url | default('', true) != '') else '' }}
+ {{ ('--images=' ~ oreg_url) if (oreg_url | default('', true) != '') else '' }}
{{ ('--nodes=' ~ openshift_node_ips | join(',')) if (openshift_node_ips | default('', true) != '') else '' }}
args:
chdir: "{{ openshift_cert_parent_dir }}"
diff --git a/roles/openshift_node/README.md b/roles/openshift_node/README.md
index 83359f164..c3c17b848 100644
--- a/roles/openshift_node/README.md
+++ b/roles/openshift_node/README.md
@@ -17,7 +17,7 @@ From this role:
| Name | Default value | |
|------------------------------------------|-----------------------|----------------------------------------|
| openshift_node_debug_level | openshift_debug_level | Verbosity of the debug logs for openshift-node |
-| openshift_registry_url | UNDEF (Optional) | Default docker registry to use |
+| oreg_url | UNDEF (Optional) | Default docker registry to use |
From openshift_common:
| Name | Default Value | |
diff --git a/roles/openshift_register_nodes/tasks/main.yml b/roles/openshift_register_nodes/tasks/main.yml
index d4d72d126..dcb96bbf9 100644
--- a/roles/openshift_register_nodes/tasks/main.yml
+++ b/roles/openshift_register_nodes/tasks/main.yml
@@ -6,15 +6,15 @@
# TODO: use a template lookup here
# TODO: create a failed_when condition
-- name: Use enterprise default for openshift_registry_url if not set
+- name: Use enterprise default for oreg_url if not set
set_fact:
- openshift_registry_url: "openshift3_beta/ose-${component}:${version}"
- when: openshift.common.deployment_type == 'enterprise' and openshift_registry_url is not defined
+ oreg_url: "openshift3_beta/ose-${component}:${version}"
+ when: openshift.common.deployment_type == 'enterprise' and oreg_url is not defined
-- name: Use online default for openshift_registry_url if not set
+- name: Use online default for oreg_url if not set
set_fact:
- openshift_registry_url: "docker-registry.ops.rhcloud.com/openshift3_beta/ose-${component}:${version}"
- when: openshift.common.deployment_type == 'online' and openshift_registry_url is not defined
+ oreg_url: "docker-registry.ops.rhcloud.com/openshift3_beta/ose-${component}:${version}"
+ when: openshift.common.deployment_type == 'online' and oreg_url is not defined
- name: Create node config
command: >
@@ -30,7 +30,7 @@
--certificate-authority={{ openshift_master_ca_cert }}
--signer-serial={{ openshift_master_ca_dir }}/serial.txt
--node-client-certificate-authority={{ openshift_master_ca_cert }}
- {{ ('--images=' ~ openshift_registry_url) if openshift_registry_url is defined else '' }}
+ {{ ('--images=' ~ oreg_url) if oreg_url is defined else '' }}
--listen=https://0.0.0.0:10250
args:
chdir: "{{ openshift_cert_parent_dir }}"
diff --git a/roles/openshift_registry/README.md b/roles/openshift_registry/README.md
new file mode 100644
index 000000000..202c818b8
--- /dev/null
+++ b/roles/openshift_registry/README.md
@@ -0,0 +1,42 @@
+OpenShift Container Docker Registry
+===================================
+
+OpenShift Docker Registry service installation
+
+Requirements
+------------
+
+Running OpenShift cluster
+
+Role Variables
+--------------
+
+From this role:
+| Name | Default value | |
+|--------------------|-------------------------------------------------------|---------------------|
+| | | |
+
+From openshift_common:
+| Name | Default value | |
+|-----------------------|---------------|--------------------------------------|
+| openshift_debug_level | 0 | Global openshift debug log verbosity |
+
+
+Dependencies
+------------
+
+Example Playbook
+----------------
+
+TODO
+
+License
+-------
+
+Apache License, Version 2.0
+
+Author Information
+------------------
+
+Red Hat openshift@redhat.com
+
diff --git a/roles/openshift_registry/handlers/main.yml b/roles/openshift_registry/handlers/main.yml
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/roles/openshift_registry/handlers/main.yml
diff --git a/roles/openshift_registry/meta/main.yml b/roles/openshift_registry/meta/main.yml
new file mode 100644
index 000000000..93b6797d1
--- /dev/null
+++ b/roles/openshift_registry/meta/main.yml
@@ -0,0 +1,13 @@
+---
+galaxy_info:
+ author: OpenShift Red Hat
+ description: OpenShift Embedded Docker Registry
+ company: Red Hat, Inc.
+ license: Apache License, Version 2.0
+ min_ansible_version: 1.7
+ platforms:
+ - name: EL
+ versions:
+ - 7
+ categories:
+ - cloud
diff --git a/roles/openshift_registry/tasks/main.yml b/roles/openshift_registry/tasks/main.yml
new file mode 100644
index 000000000..7e6982d99
--- /dev/null
+++ b/roles/openshift_registry/tasks/main.yml
@@ -0,0 +1,8 @@
+---
+- set_fact: _oreg_images="--images={{ oreg_url|quote }}"
+ when: oreg_url is defined
+
+- name: Deploy OpenShift Registry
+ command: openshift admin registry --create --credentials=/var/lib/openshift/openshift.local.certificates/openshift-registry/.kubeconfig {{ _oreg_images|default() }}
+ register: _oreg_results
+ changed_when: "'service exists' not in _oreg_results.stdout"
diff --git a/roles/openshift_registry/vars/main.yml b/roles/openshift_registry/vars/main.yml
new file mode 100644
index 000000000..cd21505a4
--- /dev/null
+++ b/roles/openshift_registry/vars/main.yml
@@ -0,0 +1,2 @@
+---
+
diff --git a/roles/openshift_router/README.md b/roles/openshift_router/README.md
new file mode 100644
index 000000000..6d8ee25c6
--- /dev/null
+++ b/roles/openshift_router/README.md
@@ -0,0 +1,41 @@
+OpenShift Container Router
+==========================
+
+OpenShift Router service installation
+
+Requirements
+------------
+
+Running OpenShift cluster
+
+Role Variables
+--------------
+
+From this role:
+| Name | Default value | |
+|--------------------|-------------------------------------------------------|---------------------|
+| | | |
+
+From openshift_common:
+| Name | Default value | |
+|-----------------------|---------------|--------------------------------------|
+| openshift_debug_level | 0 | Global openshift debug log verbosity |
+
+Dependencies
+------------
+
+Example Playbook
+----------------
+
+TODO
+
+License
+-------
+
+Apache License, Version 2.0
+
+Author Information
+------------------
+
+Red Hat openshift@redhat.com
+
diff --git a/roles/openshift_router/handlers/main.yml b/roles/openshift_router/handlers/main.yml
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/roles/openshift_router/handlers/main.yml
diff --git a/roles/openshift_router/meta/main.yml b/roles/openshift_router/meta/main.yml
new file mode 100644
index 000000000..0471e5e14
--- /dev/null
+++ b/roles/openshift_router/meta/main.yml
@@ -0,0 +1,13 @@
+---
+galaxy_info:
+ author: OpenShift Red Hat
+ description: OpenShift Embedded Router
+ company: Red Hat, Inc.
+ license: Apache License, Version 2.0
+ min_ansible_version: 1.7
+ platforms:
+ - name: EL
+ versions:
+ - 7
+ categories:
+ - cloud
diff --git a/roles/openshift_router/tasks/main.yml b/roles/openshift_router/tasks/main.yml
new file mode 100644
index 000000000..f1ee99dd3
--- /dev/null
+++ b/roles/openshift_router/tasks/main.yml
@@ -0,0 +1,8 @@
+---
+- set_fact: _ortr_images="--images={{ oreg_url|quote }}"
+ when: oreg_url is defined
+
+- name: Deploy OpenShift Router
+ command: openshift ex router --create --credentials=/var/lib/openshift/openshift.local.certificates/openshift-router/.kubeconfig {{ _ortr_images|default() }}
+ register: _ortr_results
+ changed_when: "'service exists' not in _ortr_results.stdout"
diff --git a/roles/openshift_router/vars/main.yml b/roles/openshift_router/vars/main.yml
new file mode 100644
index 000000000..cd21505a4
--- /dev/null
+++ b/roles/openshift_router/vars/main.yml
@@ -0,0 +1,2 @@
+---
+
diff --git a/roles/os_zabbix/library/zbxapi.py b/roles/os_zabbix/library/zbxapi.py
index f4f52909b..b5fa5ee2b 100755
--- a/roles/os_zabbix/library/zbxapi.py
+++ b/roles/os_zabbix/library/zbxapi.py
@@ -1,4 +1,8 @@
#!/usr/bin/env python
+# vim: expandtab:tabstop=4:shiftwidth=4
+'''
+ ZabbixAPI ansible module
+'''
# Copyright 2015 Red Hat Inc.
#
@@ -17,11 +21,22 @@
# 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):
'''
@@ -69,23 +84,26 @@ class ZabbixAPI(object):
'Usermedia': ['get'],
}
- def __init__(self, data={}):
- self.server = data['server'] or None
- self.username = data['user'] or None
- self.password = data['password'] or None
- if any(map(lambda value: value == None, [self.server, self.username, self.password])):
+ 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.has_key('verbose')
+ self.verbose = data.get('verbose', False)
self.use_ssl = data.has_key('use_ssl')
self.auth = None
- for class_name, method_names in self.classes.items():
- #obj = getattr(self, class_name)(self)
- #obj.__dict__
- setattr(self, class_name.lower(), getattr(self, class_name)(self))
+ 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
+ # This is permanently disabled.
results = self.user.login(user=self.username, password=self.password)
if results[0]['status'] == '200':
@@ -98,48 +116,40 @@ class ZabbixAPI(object):
print "Error in call to zabbix. Http status: {0}.".format(results[0]['status'])
sys.exit(1)
- def perform(self, method, params):
+ 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;
+ 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;
- params - parameters that will be passed to the API method;
+ 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"
- if params.has_key("http_method"):
- http_method = params['http_method']
-
jsonrpc = "2.0"
- if params.has_key('jsonrpc'):
- jsonrpc = params['jsonrpc']
-
rid = 1
- if params.has_key('id'):
- rid = params['id']
http = None
if self.use_ssl:
http = httplib2.Http()
else:
- http = httplib2.Http( disable_ssl_certificate_validation=True,)
+ http = httplib2.Http(disable_ssl_certificate_validation=True,)
- headers = params.get('headers', {})
+ headers = {}
headers["Content-type"] = "application/json"
body = {
"jsonrpc": jsonrpc,
"method": method,
- "params": params,
+ "params": rpc_params.get('params', {}),
"id": rid,
'auth': self.auth,
}
- if method in ['user.login','api.version']:
+ if method in ['user.login', 'api.version']:
del body['auth']
body = json.dumps(body)
@@ -150,48 +160,70 @@ class ZabbixAPI(object):
print headers
httplib2.debuglevel = 1
- response, results = http.request(self.server, http_method, body, headers)
+ 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 results
+ print content
try:
- results = json.loads(results)
- except ValueError as e:
- results = {"error": e.message}
+ content = json.loads(content)
+ except ValueError as err:
+ content = {"error": err.message}
- return response, results
+ return response, content
- '''
- 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.
- '''
@staticmethod
- def meta(class_name, method_names):
- # This meta method allows a class to add methods to it.
- def meta_method(Class, method_name):
+ 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):
- return self.parent.perform(class_name.lower()+"."+method_name, params)
- template_method.__doc__ = "https://www.zabbix.com/documentation/2.4/manual/api/reference/%s/%s" % (class_name.lower(), method_name)
+ 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)
+ setattr(_class, template_method.__name__, template_method)
# This class call instantiates a subclass. e.g. User
- Class=type(class_name, (object,), { '__doc__': "https://www.zabbix.com/documentation/2.4/manual/api/reference/%s" % class_name.lower() })
- # 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.
+ _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__)
+ 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',
@@ -200,25 +232,54 @@ class ZabbixAPI(object):
# User.delete
# User.get
for method_name in method_names:
- meta_method(Class, method_name)
+ meta_method(_class, method_name)
# Return our subclass with all methods attached
- return Class
+ 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))
+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):
+ ''' Compare passed in object to results returned from zabbix
+ '''
+ terms = ['search', 'output', 'groups', 'select', 'expand']
+ regex = '(' + '|'.join(terms) + ')'
+ retval = {}
+ for key, value in from_user.items():
+ if re.findall(regex, key):
+ continue
+
+ if 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(
+ 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()),
- action=dict(default=None, type='str'),
params=dict(),
debug=dict(default=False, type='bool'),
+ state=dict(default='present', type='str'),
),
#supports_check_mode=True
)
@@ -227,47 +288,83 @@ def main():
if not user:
user = os.environ['ZABBIX_USER']
- pw = module.params.get('password', None)
- if not pw:
- pw = os.environ['ZABBIX_PASSWORD']
+ passwd = module.params.get('password', None)
+ if not passwd:
+ passwd = os.environ['ZABBIX_PASSWORD']
- server = module.params['server']
- if module.params['debug']:
- options['debug'] = True
api_data = {
'user': user,
- 'password': pw,
- 'server': server,
+ 'password': passwd,
+ 'server': module.params['server'],
+ 'verbose': module.params['debug']
}
- if not user or not pw or not server:
- module.fail_json('Please specify the user, password, and the zabbix server.')
+ 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)
zbx_class = module.params.get('zbx_class')
- action = module.params.get('action')
- params = module.params.get('params', {})
-
+ 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())
- # Get the instance's method we are trying to call
- zbx_action_method = zapi.__getattribute__(zbx_class.capitalize()).__dict__[action]
- # Make the call with the incoming params
- results = zbx_action_method(zbx_class_inst, **params)
-
- # Results Section
- changed_state = False
- status = results[0]['status']
- if status not in ['200', '201']:
- #changed_state = False
- module.fail_json(msg="Http response: [%s] - Error: %s" % (str(results[0]), results[1]))
- module.exit_json(**{'results': results[1]['result']})
+ # 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)
+ 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()