New module: Add Sensu Silence module (monitoring/sensu_silence.py) (#24332)

* adding module to control management of sensu silence entries

* adding doc stanza

* fixing some issues

* more cleanup

* fixing defaults

* fixing more doc issues

* fixing examples

* more fixes
This commit is contained in:
Steven Bambling 2017-05-26 06:49:52 -04:00 committed by John R Barker
parent d5b04aa1f1
commit 330ad92425

View file

@ -0,0 +1,311 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Steven Bambling <smbambling@gmail.com>
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
ANSIBLE_METADATA = {'metadata_version': '1.0',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: sensu_silence
version_added: "2.4"
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.
options:
check:
description:
- Specifies the check which the silence entry applies to.
creator:
description:
- Specifies the entity responsible for this entry.
expire:
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:
description:
- If specified, this free-form string is used to provide context or
rationale for the reason this silence entry was created.
state:
description:
- Specifies to create or clear (delete) a silence entry via the Sensu API
required: true
default: present
choices: ['present', 'absent']
subscription:
description:
- Specifies the subscription which the silence entry applies to.
- To create a silence entry for a client append C(client:) to client name.
Example - C(client:server1.example.dev)
required: true
default: []
url:
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
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
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
sensu_silence:
subscription: "client:{{ item.key }}"
reason: "{{ item.value.reason }}"
creator: "{{ ansible_user_id }}"
with_dict: "{{ silence }}"
'''
RETURN = '''
'''
try:
import json
except ImportError:
import simplejson as json
# import module snippets
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(response.read())
except:
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 = dict((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(response.read())
except:
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(response.read())
except:
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(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()