From b167f7b3c4082a3d990aabeb10faac888e7172b3 Mon Sep 17 00:00:00 2001 From: Jason DeTiberus Date: Tue, 7 Apr 2015 22:34:00 -0400 Subject: move zbxapi module to a new os_zabbix role - cleans up repo root a bit --- library/zbxapi.py | 273 ---------------------------- playbooks/adhoc/noc/get_zabbix_problems.yml | 4 +- playbooks/adhoc/noc/library | 1 - playbooks/adhoc/noc/roles | 1 + roles/os_zabbix/library/zbxapi.py | 273 ++++++++++++++++++++++++++++ 5 files changed, 277 insertions(+), 275 deletions(-) delete mode 100755 library/zbxapi.py delete mode 120000 playbooks/adhoc/noc/library create mode 120000 playbooks/adhoc/noc/roles create mode 100755 roles/os_zabbix/library/zbxapi.py diff --git a/library/zbxapi.py b/library/zbxapi.py deleted file mode 100755 index f4f52909b..000000000 --- a/library/zbxapi.py +++ /dev/null @@ -1,273 +0,0 @@ -#!/usr/bin/env python - -# 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. -# - -import json -import httplib2 -import sys -import os -import re - -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={}): - 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])): - print 'Please specify zabbix server url, username, and password.' - sys.exit(1) - - self.verbose = data.has_key('verbose') - 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)) - - 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, 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; - 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,) - - headers = params.get('headers', {}) - headers["Content-type"] = "application/json" - - body = { - "jsonrpc": jsonrpc, - "method": method, - "params": 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, results = http.request(self.server, http_method, body, headers) - - if self.verbose: - print response - print results - - try: - results = json.loads(results) - except ValueError as e: - results = {"error": e.message} - - return response, results - - ''' - 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): - # 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) - 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(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. - def __init__(self, parent): - 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 main(): - - 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()), - action=dict(default=None, type='str'), - params=dict(), - debug=dict(default=False, type='bool'), - ), - #supports_check_mode=True - ) - - user = module.params.get('user', None) - if not user: - user = os.environ['ZABBIX_USER'] - - pw = module.params.get('password', None) - if not pw: - pw = os.environ['ZABBIX_PASSWORD'] - - server = module.params['server'] - - if module.params['debug']: - options['debug'] = True - - api_data = { - 'user': user, - 'password': pw, - 'server': server, - } - - if not user or not pw or not server: - module.fail_json('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', {}) - - - # 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']}) - -from ansible.module_utils.basic import * - -main() diff --git a/playbooks/adhoc/noc/get_zabbix_problems.yml b/playbooks/adhoc/noc/get_zabbix_problems.yml index 6ac5cdcf7..02bffc1d2 100644 --- a/playbooks/adhoc/noc/get_zabbix_problems.yml +++ b/playbooks/adhoc/noc/get_zabbix_problems.yml @@ -2,7 +2,9 @@ - name: 'Get current hosts who have triggers that are alerting by trigger description' hosts: localhost gather_facts: no - tasks: + roles: + - os_zabbix + post_tasks: - assert: that: oo_desc is defined diff --git a/playbooks/adhoc/noc/library b/playbooks/adhoc/noc/library deleted file mode 120000 index ba40d2f56..000000000 --- a/playbooks/adhoc/noc/library +++ /dev/null @@ -1 +0,0 @@ -../../../library \ No newline at end of file diff --git a/playbooks/adhoc/noc/roles b/playbooks/adhoc/noc/roles new file mode 120000 index 000000000..20c4c58cf --- /dev/null +++ b/playbooks/adhoc/noc/roles @@ -0,0 +1 @@ +../../../roles \ No newline at end of file diff --git a/roles/os_zabbix/library/zbxapi.py b/roles/os_zabbix/library/zbxapi.py new file mode 100755 index 000000000..f4f52909b --- /dev/null +++ b/roles/os_zabbix/library/zbxapi.py @@ -0,0 +1,273 @@ +#!/usr/bin/env python + +# 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. +# + +import json +import httplib2 +import sys +import os +import re + +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={}): + 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])): + print 'Please specify zabbix server url, username, and password.' + sys.exit(1) + + self.verbose = data.has_key('verbose') + 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)) + + 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, 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; + 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,) + + headers = params.get('headers', {}) + headers["Content-type"] = "application/json" + + body = { + "jsonrpc": jsonrpc, + "method": method, + "params": 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, results = http.request(self.server, http_method, body, headers) + + if self.verbose: + print response + print results + + try: + results = json.loads(results) + except ValueError as e: + results = {"error": e.message} + + return response, results + + ''' + 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): + # 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) + 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(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. + def __init__(self, parent): + 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 main(): + + 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()), + action=dict(default=None, type='str'), + params=dict(), + debug=dict(default=False, type='bool'), + ), + #supports_check_mode=True + ) + + user = module.params.get('user', None) + if not user: + user = os.environ['ZABBIX_USER'] + + pw = module.params.get('password', None) + if not pw: + pw = os.environ['ZABBIX_PASSWORD'] + + server = module.params['server'] + + if module.params['debug']: + options['debug'] = True + + api_data = { + 'user': user, + 'password': pw, + 'server': server, + } + + if not user or not pw or not server: + module.fail_json('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', {}) + + + # 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']}) + +from ansible.module_utils.basic import * + +main() -- cgit v1.2.3