#!/usr/bin/python # -*- coding: utf-8 -*- # Copyright (c) 2017, Steven Bambling # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later from __future__ import absolute_import, division, print_function __metaclass__ = type DOCUMENTATION = ''' --- module: sensu_silence author: Steven Bambling (@smbambling) short_description: Manage Sensu silence entries description: - Create and clear (delete) a silence entries via the Sensu API for subscriptions and checks. extends_documentation_fragment: - community.general.attributes attributes: check_mode: support: full diff_mode: support: none options: check: type: str description: - Specifies the check which the silence entry applies to. creator: type: str description: - Specifies the entity responsible for this entry. expire: type: int description: - If specified, the silence entry will be automatically cleared after this number of seconds. expire_on_resolve: description: - If specified as true, the silence entry will be automatically cleared once the condition it is silencing is resolved. type: bool reason: type: str description: - If specified, this free-form string is used to provide context or rationale for the reason this silence entry was created. state: type: str description: - Specifies to create or clear (delete) a silence entry via the Sensu API default: present choices: ['present', 'absent'] subscription: type: str description: - Specifies the subscription which the silence entry applies to. - To create a silence entry for a client prepend C(client:) to client name. Example - C(client:server1.example.dev) required: true url: type: str description: - Specifies the URL of the Sensu monitoring host server. required: false default: http://127.0.01:4567 ''' EXAMPLES = ''' # Silence ALL checks for a given client - name: Silence server1.example.dev community.general.sensu_silence: subscription: client:server1.example.dev creator: "{{ ansible_user_id }}" reason: Performing maintenance # Silence specific check for a client - name: Silence CPU_Usage check for server1.example.dev community.general.sensu_silence: subscription: client:server1.example.dev check: CPU_Usage creator: "{{ ansible_user_id }}" reason: Investigation alert issue # Silence multiple clients from a dict silence: server1.example.dev: reason: 'Deployment in progress' server2.example.dev: reason: 'Deployment in progress' - name: Silence several clients from a dict community.general.sensu_silence: subscription: "client:{{ item.key }}" reason: "{{ item.value.reason }}" creator: "{{ ansible_user_id }}" with_dict: "{{ silence }}" ''' RETURN = ''' ''' import json from ansible.module_utils.common.text.converters import to_native from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.urls import fetch_url def query(module, url, check, subscription): headers = { 'Content-Type': 'application/json', } url = url + '/silenced' request_data = { 'check': check, 'subscription': subscription, } # Remove keys with None value for k, v in dict(request_data).items(): if v is None: del request_data[k] response, info = fetch_url( module, url, method='GET', headers=headers, data=json.dumps(request_data) ) if info['status'] == 500: module.fail_json( msg="Failed to query silence %s. Reason: %s" % (subscription, info) ) try: json_out = json.loads(to_native(response.read())) except Exception: json_out = "" return False, json_out, False def clear(module, url, check, subscription): # Test if silence exists before clearing (rc, out, changed) = query(module, url, check, subscription) d = {i['subscription']: i['check'] for i in out} subscription_exists = subscription in d if check and subscription_exists: exists = (check == d[subscription]) else: exists = subscription_exists # If check/subscription doesn't exist # exit with changed state of False if not exists: return False, out, changed # module.check_mode is inherited from the AnsibleMOdule class if not module.check_mode: headers = { 'Content-Type': 'application/json', } url = url + '/silenced/clear' request_data = { 'check': check, 'subscription': subscription, } # Remove keys with None value for k, v in dict(request_data).items(): if v is None: del request_data[k] response, info = fetch_url( module, url, method='POST', headers=headers, data=json.dumps(request_data) ) if info['status'] != 204: module.fail_json( msg="Failed to silence %s. Reason: %s" % (subscription, info) ) try: json_out = json.loads(to_native(response.read())) except Exception: json_out = "" return False, json_out, True return False, out, True def create( module, url, check, creator, expire, expire_on_resolve, reason, subscription): (rc, out, changed) = query(module, url, check, subscription) for i in out: if (i['subscription'] == subscription): if ( (check is None or check == i['check']) and ( creator == '' or creator == i['creator']) and ( reason == '' or reason == i['reason']) and ( expire is None or expire == i['expire']) and ( expire_on_resolve is None or expire_on_resolve == i['expire_on_resolve'] ) ): return False, out, False # module.check_mode is inherited from the AnsibleMOdule class if not module.check_mode: headers = { 'Content-Type': 'application/json', } url = url + '/silenced' request_data = { 'check': check, 'creator': creator, 'expire': expire, 'expire_on_resolve': expire_on_resolve, 'reason': reason, 'subscription': subscription, } # Remove keys with None value for k, v in dict(request_data).items(): if v is None: del request_data[k] response, info = fetch_url( module, url, method='POST', headers=headers, data=json.dumps(request_data) ) if info['status'] != 201: module.fail_json( msg="Failed to silence %s. Reason: %s" % (subscription, info['msg']) ) try: json_out = json.loads(to_native(response.read())) except Exception: json_out = "" return False, json_out, True return False, out, True def main(): module = AnsibleModule( argument_spec=dict( check=dict(required=False), creator=dict(required=False), expire=dict(type='int', required=False), expire_on_resolve=dict(type='bool', required=False), reason=dict(required=False), state=dict(default='present', choices=['present', 'absent']), subscription=dict(required=True), url=dict(required=False, default='http://127.0.01:4567'), ), supports_check_mode=True ) url = module.params['url'] check = module.params['check'] creator = module.params['creator'] expire = module.params['expire'] expire_on_resolve = module.params['expire_on_resolve'] reason = module.params['reason'] subscription = module.params['subscription'] state = module.params['state'] if state == 'present': (rc, out, changed) = create( module, url, check, creator, expire, expire_on_resolve, reason, subscription ) if state == 'absent': (rc, out, changed) = clear(module, url, check, subscription) if rc != 0: module.fail_json(msg="failed", result=out) module.exit_json(msg="success", result=out, changed=changed) if __name__ == '__main__': main()