forked from Linuxfabrik/lib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
icinga.py
225 lines (194 loc) · 7.07 KB
/
icinga.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
#! /usr/bin/env python3
# -*- coding: utf-8; py-indent-offset: 4 -*-
#
# Author: Linuxfabrik GmbH, Zurich, Switzerland
# Contact: info (at) linuxfabrik (dot) ch
# https://www.linuxfabrik.ch/
# License: The Unlicense, see LICENSE file.
# https://github.com/Linuxfabrik/monitoring-plugins/blob/main/CONTRIBUTING.rst
"""This module tries to make accessing the Icinga2 API easier.
"""
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
__version__ = '2024031401'
import base64
import time
from . import txt
from . import url
# Take care of Icinga and throttle the amount of requests, don't overload it
# with too fast subsequent api-calls.
DEFAULT_SLEEP = 1.0
def api_post(uri, username, password, data={}, method_override='',
insecure=False, no_proxy=False, timeout=3):
"""POST a low level (handmade) request to the Icinga API.
Example:
>>> uri = 'https://icinga-server:5665/v1/objects/services'
>>> data = {
>>> 'filter': 'match("special-service", service.name)',
>>> 'attrs': [ 'name', 'state', 'acknowledgement' ],
>>> }
>>> result = lib.base.coe(lib.icinga.api_post(uri, args.USERNAME,
>>> args.PASSWORD, data=data,
>>> method_override='GET', timeout=3))
"""
uri = uri.replace('//v1', '/v1').replace('//v2', '/v2')
header = {}
header['Accept'] = 'application/json'
auth = '{}:{}'.format(username, password)
encoded_auth = txt.to_text(base64.b64encode(txt.to_bytes(auth)))
header['Authorization'] = 'Basic {}'.format(encoded_auth)
if method_override:
header['X-HTTP-Method-Override'] = method_override
result = url.fetch_json(
uri,
data=data,
encoding='serialized-json',
header=header,
insecure=insecure,
no_proxy=no_proxy,
timeout=timeout,
)
time.sleep(DEFAULT_SLEEP)
return result
def get_service(uri, username, password, servicename, attrs='state',
insecure=False, no_proxy=False, timeout=3):
"""POST a high level request to the Icinga `objects/service` API
(with less possibilities). The service name should be unique and has
to be taken from the `__name` attribute.
Example: Does a check show a warning and/or was acknowledged?
>>> uri = 'https://icinga-server:5665'
>>> result = lib.base.coe(
>>> lib.icinga.get_service(
>>> uri,
>>> args.USERNAME,
>>> args.PASSWORD,
>>> servicename='hostname!special-service',
>>> attrs='state,acknowledgement',
>>> ))
>>> print(result['result'][0]['attrs'])
"""
uri = uri + '/v1/objects/services'
data = {
'filter': 'match("{}", service.__name)'.format(servicename),
'attrs': ['name'] + attrs.split(','),
}
return api_post(
uri=uri,
username=username,
password=password,
data=data,
method_override='GET',
insecure=insecure,
no_proxy=no_proxy,
timeout=timeout,
)
def set_ack(uri, username, password, objectname, _type='service', author='Linuxfabrik lib.icinga',
insecure=False, no_proxy=False, timeout=3):
"""Allows you to acknowledge the current problem for hosts or
services. By acknowledging the current problem, future notifications
(for the same state if sticky is set to false) are disabled. The
host or service name should be unique and has to be taken from the
`__name` attribute.
Acknowledging an already acknowledged problem is ok until 2.11, while
acknowleding a host or service in OK state leads to a *500 internal
server error".
"""
uri = uri + '/v1/actions/acknowledge-problem'
data = {
'type': _type.capitalize(),
'filter': 'match("{}", {}.__name)'.format(objectname, _type.lower()),
'author': author,
'comment': 'automatically acknowledged',
'notify': False,
}
return api_post(
uri=uri,
username=username,
password=password,
data=data,
insecure=insecure,
no_proxy=no_proxy,
timeout=timeout,
)
def set_downtime(uri, username, password, objectname, _type='service',
starttime=int(time.time()), endtime=int(time.time())+60*60,
author='Linuxfabrik lib.icinga',
insecure=False, no_proxy=False, timeout=3):
"""POST a high level request to the Icinga `actions/schedule-downtime
API (with less possibilities). The host or service name should be
unique and has to be taken from the `__name` attribute.
You will get a downtime name, which you have to use if you want to
use `remove_ack()` later on.
>>> uri = 'https://icinga-server:5665'
>>> result = lib.base.coe(lib.icinga.set_downtime(
>>> uri,
>>> args.ICINGA_USERNAME,
>>> args.ICINGA_PASSWORD,
>>> objectname='hostname!special-service',
>>> author='feed plugin',
>>> ))
'hostname!special-service!3ad20784-52f9-4acc-b2df-90788667d587'
"""
uri = uri + '/v1/actions/schedule-downtime'
data = {
'type': _type.capitalize(),
'filter': 'match("{}", {}.__name)'.format(objectname, _type.lower()),
'author': author,
'comment': 'automatic downtime',
'start_time': starttime,
'end_time': endtime,
}
success, result = api_post(
uri=uri,
username=username,
password=password,
data=data,
insecure=insecure,
no_proxy=no_proxy,
timeout=timeout,
)
if success and result['results'][0]['code'] == 200:
return (True, result['results'][0]['name'])
return (False, result)
def remove_ack(uri, username, password, objectname, _type='service',
insecure=False, no_proxy=False, timeout=3):
"""Removes the acknowledgements for services or hosts. Once the
acknowledgement has been removed the next notification will be sent
again. Always returns ok.
>>> uri = 'https://icinga-server:5665'
>>> icinga.remove_ack(
>>> uri,
>>> args.ICINGA_USERNAME,
>>> args.ICINGA_PASSWORD,
>>> objectname='hostname!special-service',
>>> )
"""
uri = uri + '/v1/actions/remove-acknowledgement'
data = {
'type': _type.capitalize(),
'filter': 'match("{}", {}.__name)'.format(objectname, _type.lower()),
}
return api_post(uri=uri,
username=username,
password=password,
data=data,
insecure=insecure,
no_proxy=no_proxy,
timeout=timeout,
)
def remove_downtime(uri, username, password, downtime,
insecure=False, no_proxy=False, timeout=3):
"""Remove the downtime using its name you got from `set_downtime()`.
Always returns ok.
"""
uri = uri + '/v1/actions/remove-downtime'
data = {
'downtime': downtime,
}
return api_post(uri=uri,
username=username,
password=password,
data=data,
insecure=insecure,
no_proxy=no_proxy,
timeout=timeout,
)