Skip to content

Commit 005cee2

Browse files
committed
Error-checking, pep8 conformance and linting
1 parent 104b972 commit 005cee2

File tree

3 files changed

+83
-40
lines changed

3 files changed

+83
-40
lines changed

requirements_test.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ nose
33
pep8
44
pylint
55
coverage
6+
requests

sensu_plugin/handler.py

Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,27 @@
66
# Released under the same terms as Sensu (the MIT license); see LICENSE
77
# for details.
88

9+
'''
10+
This provides a base SensuHandler class that can be used for writing
11+
python-based Sensu handlers.
12+
'''
13+
914
from __future__ import print_function
1015
import os
1116
import sys
17+
import json
1218
import requests
1319
try:
1420
from urlparse import urlparse
1521
except ImportError:
1622
from urllib.parse import urlparse
17-
from utils import *
23+
from sensu_plugin.utils import get_settings
1824

1925

2026
class SensuHandler(object):
27+
'''
28+
Class to be used as a basis for handlers.
29+
'''
2130
def __init__(self):
2231
# Parse the stdin into a global event object
2332
stdin = sys.stdin.read()
@@ -40,8 +49,8 @@ def read_event(self, check_result):
4049
self.event['occurrences'] = self.event.get('occurrences', 1)
4150
self.event['check'] = self.event.get('check', {})
4251
self.event['client'] = self.event.get('client', {})
43-
except Exception as e:
44-
print('error reading event: ' + e.message)
52+
except Exception as exception: # pylint: disable=broad-except
53+
print('error reading event: ' + exception)
4554
sys.exit(1)
4655

4756
def handle(self):
@@ -63,7 +72,7 @@ def filter(self):
6372
self.filter_silenced()
6473
self.filter_dependencies()
6574

66-
if self.deprecated_occurrence_filtering_enabled():
75+
if self.deprecated_occurrence_filtering():
6776
print('warning: occurrence filtering in sensu-plugin is' +
6877
'deprecated, see http://bit.ly/sensu-plugin')
6978
self.filter_repeated()
@@ -78,7 +87,7 @@ def deprecated_filtering_enabled(self):
7887
'''
7988
return self.event['check'].get('enable_deprecated_filtering', False)
8089

81-
def deprecated_occurrence_filtering_enabled(self):
90+
def deprecated_occurrence_filtering(self):
8291
'''
8392
Evaluates whether the event should be processed by the
8493
filter_repeated method. Defaults to true, i.e. filter_repeated
@@ -94,23 +103,23 @@ def bail(self, msg):
94103
'''
95104
Gracefully terminate with message
96105
'''
97-
client_name = self.event['client'].get('name', 'error:no-client-name')
106+
client_name = self.event.get('client', 'error:no-client-name')
98107
check_name = self.event['client'].get('name', 'error:no-check-name')
99108
print('{}: {}/{}'.format(msg, client_name, check_name))
100109
sys.exit(0)
101110

102111
def get_api_settings(self):
103112
'''
104-
Return a hash of API settings derived first from ENV['SENSU_API_URL']
113+
Return a hash of API settings derived first from ENV['sensu_api_url']
105114
if set, then Sensu config `api` scope if configured, and finally
106115
falling back to to ipv4 localhost address on default API port.
107116
108117
return dict
109118
'''
110119

111-
SENSU_API_URL = os.environ.get('SENSU_API_URL')
112-
if SENSU_API_URL:
113-
uri = urlparse(SENSU_API_URL)
120+
sensu_api_url = os.environ.get('sensu_api_url')
121+
if sensu_api_url:
122+
uri = urlparse(sensu_api_url)
114123
self.api_settings = {
115124
'host': '{0}//{1}'.format(uri.scheme, uri.hostname),
116125
'port': uri.port,
@@ -125,7 +134,10 @@ def get_api_settings(self):
125134
'port', 4567)
126135

127136
# API requests
128-
def api_request(method, path, blk):
137+
def api_request(self, method, path):
138+
'''
139+
Query Sensu api for information.
140+
'''
129141
if not hasattr(self, 'api_settings'):
130142
ValueError('api.json settings not found')
131143

@@ -135,7 +147,6 @@ def api_request(method, path, blk):
135147
_request = requests.post
136148

137149
domain = self.api_settings['host']
138-
# TODO: http/https
139150
uri = 'http://{}:{}{}'.format(domain, self.api_settings['port'], path)
140151
if self.api_settings['user'] and self.api_settings['password']:
141152
auth = (self.api_settings['user'], self.api_settings['password'])
@@ -145,19 +156,32 @@ def api_request(method, path, blk):
145156
return req
146157

147158
def stash_exists(self, path):
159+
'''
160+
Query Sensu API for stash data.
161+
'''
148162
return self.api_request('get', '/stash' + path).status_code == 200
149163

150164
def event_exists(self, client, check):
151-
return self.api_request('get',
152-
'/events/{}/{}'.format(client, check)
153-
).status_code == 200
165+
'''
166+
Query Sensu API for event.
167+
'''
168+
return self.api_request(
169+
'get',
170+
'events/{}/{}'.format(client, check)
171+
).status_code == 200
154172

155173
# Filters
156174
def filter_disabled(self):
175+
'''
176+
Determine whether a check is disabled and shouldn't handle.
177+
'''
157178
if self.event['check']['alert'] is False:
158-
bail('alert disabled')
179+
self.bail('alert disabled')
159180

160181
def filter_silenced(self):
182+
'''
183+
Determine whether a check is silenced and shouldn't handle.
184+
'''
161185
stashes = [
162186
('client', '/silence/{}'.format(self.event['client']['name'])),
163187
('check', '/silence/{}/{}'.format(
@@ -166,17 +190,18 @@ def filter_silenced(self):
166190
('check', '/silence/all/{}'.format(self.event['check']['name']))
167191
]
168192
for scope, path in stashes:
169-
if stash_exists(path):
170-
bail(scope + ' alerts silenced')
171-
# TODO: Timeout for querying Sensu API?
172-
# More appropriate in the api_request method?
193+
if self.stash_exists(path):
194+
self.bail(scope + ' alerts silenced')
173195

174196
def filter_dependencies(self):
197+
'''
198+
Determine whether a check has dependencies.
199+
'''
175200
dependencies = self.event['check'].get('dependencies', None)
176201
if dependencies is None or not isinstance(dependencies, list):
177202
return
178203
for dependency in self.event['check']['dependencies']:
179-
if len(str(dependency)) == 0:
204+
if not str(dependency):
180205
continue
181206
dependency_split = tuple(dependency.split('/'))
182207
# If there's a dependency on a check from another client, then use
@@ -187,9 +212,12 @@ def filter_dependencies(self):
187212
client = self.event['client']['name']
188213
check = dependency_split[0]
189214
if self.event_exists(client, check):
190-
bail('check dependency event exists')
215+
self.bail('check dependency event exists')
191216

192217
def filter_repeated(self):
218+
'''
219+
Determine whether a check is repeating.
220+
'''
193221
defaults = {
194222
'occurrences': 1,
195223
'interval': 30,
@@ -198,8 +226,7 @@ def filter_repeated(self):
198226

199227
# Override defaults with anything defined in the settings
200228
if isinstance(self.settings['sensu_plugin'], dict):
201-
defaults.update(settings['sensu_plugin'])
202-
end
229+
defaults.update(self.settings['sensu_plugin'])
203230

204231
occurrences = int(self.event['check'].get(
205232
'occurrences', defaults['occurrences']))
@@ -209,7 +236,7 @@ def filter_repeated(self):
209236
'refresh', defaults['refresh']))
210237

211238
if self.event['occurrences'] < occurrences:
212-
bail('not enough occurrences')
239+
self.bail('not enough occurrences')
213240

214241
if (self.event['occurrences'] > occurrences and
215242
self.event['action'] == 'create'):
@@ -220,4 +247,4 @@ def filter_repeated(self):
220247
(self.event['occurrences'] - occurrences) % number == 0):
221248
return
222249

223-
bail('only handling every ' + str(number) + ' occurrences')
250+
self.bail('only handling every ' + str(number) + ' occurrences')

sensu_plugin/utils/__init__.py

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,34 @@
1+
'''
2+
Utilities for loading config files, etc.
3+
'''
4+
15
import os
26
import json
37

48

59
def config_files():
6-
SENSU_LOADED_TEMPFILE = os.environ.get('SENSU_LOADED_TEMPFILE')
7-
SENSU_CONFIG_FILES = os.environ.get('SENSU_CONFIG_FILES')
8-
if SENSU_LOADED_TEMPFILE and os.path.isfile(SENSU_LOADED_TEMPLATE):
9-
with open(SENSU_LOADED_TEMPLATE, 'r') as template:
10-
contents = template.read()
10+
'''
11+
Get list of currently used config files.
12+
'''
13+
sensu_loaded_tempfile = os.environ.get('SENSU_LOADED_TEMPFILE')
14+
sensu_config_files = os.environ.get('SENSU_CONFIG_FILES')
15+
if sensu_loaded_tempfile and os.path.isfile(sensu_loaded_tempfile):
16+
with open(sensu_loaded_tempfile, 'r') as tempfile:
17+
contents = tempfile.read()
1118
return contents.split(':')
12-
elif SENSU_CONFIG_FILES:
13-
return SENSU_CONFIG_FILES.split(':')
19+
elif sensu_config_files:
20+
return sensu_config_files.split(':')
1421
else:
1522
files = ['/etc/sensu/config.json']
16-
[files.append('/etc/sensu/conf.d/{}'.format(filename))
17-
for filename in os.listdir('/etc/sensu/conf.d')
18-
if os.path.splitext(filename)[1] == '.json']
19-
return files
23+
return [files.append('/etc/sensu/conf.d/{}'.format(filename))
24+
for filename in os.listdir('/etc/sensu/conf.d')
25+
if os.path.splitext(filename)[1] == '.json']
2026

2127

2228
def get_settings():
29+
'''
30+
Get all currently loaded settings.
31+
'''
2332
settings = {}
2433
for config_file in config_files():
2534
config_contents = load_config(config_file)
@@ -29,19 +38,25 @@ def get_settings():
2938

3039

3140
def load_config(filename):
41+
'''
42+
Read contents of config file.
43+
'''
3244
try:
3345
with open(filename, 'r') as config_file:
3446
return json.loads(config_file.read())
35-
except FileNotFoundError:
36-
{}
47+
except IOError:
48+
pass
3749

3850

3951
def deep_merge(dict_one, dict_two):
52+
'''
53+
Deep merge two dicts.
54+
'''
4055
merged = dict_one.copy()
4156
for key, value in dict_two.items():
4257
# value is equivalent to dict_two[key]
4358
if (key in dict_one and
44-
isinstance(dict_one[key], dict) and
59+
isinstance(dict_one[key], dict) and
4560
isinstance(value, dict)):
4661
merged[key] = deep_merge(dict_one[key], value)
4762
elif (key in dict_one and

0 commit comments

Comments
 (0)