#!/usr/bin/python # 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 annotations DOCUMENTATION = r""" module: sensu_silence author: Steven Bambling (@smbambling) short_description: Manage Sensu silence entries description: - Create and clear (delete) a silence entries using the Sensu API for subscriptions and checks. deprecated: removed_in: 13.0.0 why: Sensu Core and Sensu Enterprise products have been End of Life since 2019/20. alternative: Use Sensu Go and its accompanying collection C(sensu.sensu_go). 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 is automatically cleared after this number of seconds. expire_on_resolve: description: - If specified as true, the silence entry is 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 using 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. default: http://127.0.01:4567 """ EXAMPLES = r""" # 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 = r""" """ import json 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=f"Failed to query silence {subscription}. Reason: {info}") try: json_out = json.loads(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=f"Failed to silence {subscription}. Reason: {info}") try: json_out = json.loads(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=f"Failed to silence {subscription}. Reason: {info['msg']}") try: json_out = json.loads(response.read()) except Exception: json_out = "" return False, json_out, True return False, out, True def main(): module = AnsibleModule( argument_spec=dict( check=dict(), creator=dict(), expire=dict(type="int"), expire_on_resolve=dict(type="bool"), reason=dict(), state=dict(default="present", choices=["present", "absent"]), subscription=dict(required=True), url=dict(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()